From 6fe91ef7b61c74e378ed5c0d0058534186d2a0f7 Mon Sep 17 00:00:00 2001 From: Thomas Kaiser Date: Sun, 28 Feb 2016 18:17:17 +0100 Subject: [PATCH 01/15] Enable board/settings mismatch detection for sun8i (trial balloon) --- scripts/armhwinfo | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/scripts/armhwinfo b/scripts/armhwinfo index 935305c42d..bd05db902b 100644 --- a/scripts/armhwinfo +++ b/scripts/armhwinfo @@ -13,6 +13,15 @@ if [ "X$1" != "Xstart" ]; then exit 1 fi +create_motd_warning() { +cat > /etc/update-motd.d/90-warning <"${TMPFILE}" @@ -156,11 +165,12 @@ if [ "$ARCH" = "armv7l" ]; then fi # prepare board/settings mismatch detection. If we cleanup board/config names then this # might work for all boards later and can be moved from sun8i section further down to support - # all $HARDWARE variants + # all $HARDWARE variants. Only check board after 1st login already happened to be not in + # conflict with our board auto detection mechanisms ScriptBinName="$(echo "${ID}" | tr '[:upper:]' '[:lower:]' | sed -e 's/+/plus/' -e 's/\ //g' -e 's/2mini$/2/g' -e 's/plus2$/plus/g').bin" ScriptBinUsed="$(readlink -f "/boot/script.bin")" - if [ "X${ScriptBinName}" != "X${ScriptBinUsed##*/}" ]; then - : + if [ "X${ScriptBinName}" != "X${ScriptBinUsed##*/}" -a ! -f "/root/.not_logged_in_yet" ]; then + create_motd_warning "It seems the image is running on ${ID} but you're using wrong settings: ${ScriptBinUsed##*/}" fi fi fi From a0f44ac5f6f7b9e99b58b4ab93105881159a0984 Mon Sep 17 00:00:00 2001 From: Igor Pecovnik Date: Sun, 28 Feb 2016 18:48:01 +0100 Subject: [PATCH 02/15] Fixed Bluetooth on Cubietruck --- bin/brcm_bt_reset | Bin 0 -> 8606 bytes bin/brcm_patchram_plus | Bin 16943 -> 20238 bytes scripts/brcm40183-patch | 3 +++ 3 files changed, 3 insertions(+) create mode 100644 bin/brcm_bt_reset diff --git a/bin/brcm_bt_reset b/bin/brcm_bt_reset new file mode 100644 index 0000000000000000000000000000000000000000..885d49f1f7c33e4725209ad54de0e15f58369568 GIT binary patch literal 8606 zcmb_h4RBP~b-r(RL9#4^0AUMIomT@L63_y+9Am&nLShA2ND9b}Y3w}S?mlTB-oNZV zVaXykv6;k^Ff~qS>m+WR%y=?($Byk5Tv8yoN!+F#r^Ur-+zf4$6ly|1NQ@%Mmc#b@ z-hEekdL^B9#z(q)?sw0*=l-7i?$4u}T4S1~2}L2XOc3oX(?mV^@!3LzB4S3p&_y|9 z9}%^b=ijUp;>}9U4du{dh8&#hnN(M_n2X-V475QV*0H7SUi_l}5SUj-pu8G^eL(q7cmDAM zEsc#ou6uF&ORrsAx;^*ro1U2i*-Z%OdY5M5cdi##>^d(p51h7H28rXq@+$~DlKm#c zjVb}0<&(-JbL;Cx#e76=Kwv$tM?hCjBh?1VSuQc{G|lXY%xTzvx z^-?-aW8IZa)|GY?v7Kxa`-t_8zi58*p`U(z@9wtm|IHWA4%UA5(wy0MKk}!0?|rl4 z@o3v!qxo0Aws*sOrQ@G|XaDInSH4uc{lK!{*A~C`+$T?eJMyh(Uzq)=udSP1y12jk z=<)~WFM9pDr*68i=PJxjqt|>$M|^`1vp#(R{G9;)!vN;kDPn&1p(5g26aXiFCV+o0 zfFB9q2LpHuaKo&SI}UT;Ne=|%(E$E@0Cxm%F@QNnidf%A6#yqb7{JK@7Vwt@J>=uU z>a`t_w+e+^L74Ge!4a8^nHPz!qUG4dyk#YYVL+VC8R=ZYbnIMKI0*<%$0>-SlY~sz zxrCDz#lE6rWkgRgZCQEI^-#ffEa-Nndx|NMNau={$mOl9=*k!DtkVTiw`ayJEvHIj z<&2_Z791mE+F9C7BsFkaMwsog3kp z5ppLyiTbmK>8+C&xmvgdB^|GIA_3E66e6tH{xq@`k!! zbqMk6@_i@HM+WN7MFyTdH*4U@f%2j6o!g7=hxofEe_8d92Y$JC?D#nqcYN`*FP`+p z@At(!eeqUbyxA9D?~B*_;wyadCBAsAFJA47SNh@+U;Km7srrxj;un4Kv%dHl#M_6& z^$4><$9Kmfhqc2$AFq0S+j!*1;mwhIN@LGoE{&bJyz_cZSQYsGfmg43_FT38?78r& zCkI0MSKbw3`+weCTB-e0sdQoeOik><@v(_h2caoWQkQ{LbtKZdxOdTaOJo01(iShy zSDg?in<1OAx%@~tHSg8PJ>gfMZaHzjyrDF9`lL8HfNv@3;E_LhMZDa*t9__++eETA z)jsmM&y>bGE{`WC(tkBv+ED#g!)Qa|^(&!pZK^aDzZ{M&O6jqN(bVeKuV~uCNNc@} zysJuM>o1R|+lNA0X>4e)Y`7{so?Z|ujolBa2(L5w+wcA!GmqI#BX8_z8k!qE=B7-T z)USy(USaN!UG}3ho-O3p7Q)`eK~>7}!SLp(9NPW_7{WUSbw~K_Ya0qqxjn0?IQv$`~JLn4HM?N-MI_l&{WDX zvtjh$Dzs6^HvMR@*X*~&^75ZGj6UP0m&Tqz4NAA=2l{unUuX)yZ}-{aDecRssaOze zAA+?ZEnFIVZE%gb&Sqa$p)U`6d3O)4vl~W#aax-;e&eg(#$Kcy|7 zb4JaSMX83-Q(oU`TKmwuq0-pZOYDvMfpw|ya3s7aRf9JF?bV}bfmj~;8TvT<2Lt`7 z(DLw^(%90{_^z8=&2mrkgG=M+5wX1T)KnQYn1x3hISb#%EUXx8xw5LGH1@BTjsh(l zoInYfM{b?#el^}y7OQM~B38NWsn{dU7`aQIZQir!wW^9!k-Nkat^VHe$c8ns#@N=_ z(=CTLj=pu`{P^SIVx`8-0tMV#dN$hDC>(mcL(`qHAF$n~U?dN$|iaZBg-$x5!! z-S45kG>J8MWzyQSGK23L=-#XuPg}Z^a~1VT(NsD=o_d#^wnRR$c4@k|LbTx%su!(- zZKid%OxUv%mYy{;mTqTt$F$QG6`lB9tFQOz-K~Gh&f1P%OcdIJLVlXmpG+|E1je(6zuXG!zR zHSt@1gFyUc;GUCfDfhPbW6kB6gXf1u;M|`sL^uOn>tUuH!dU+1YALrqq`BvhWJGiK z+ati-WB)S(_jmlZbKgwj-ui8Pi@91pkHEbw_qf~_9-5)K@%`Z3J24;kyWF>5EtPUf zq?f>1-y!gN;Quf2%%f;C+WTP#Wt+UEscEggtl5g&W>&9{-VwdE?)Hz$NKm#WdRyI{ zlp!J-KaR|%WyWoxtw40f9d(UjW<^o7@H4@gB$WZ_zmn z|0{8Ra~5${$TPP*Z>vmdhAl<{&vDd~XJhOI5m!WiAgxAFdU>vOFtEgx$RDM*8IWgB z+M^#Gf*$>W=T#E*7@84AG1sX_KU)QKP&|ylvn}=L-}|A* z`Y3yBEB*X&1nO->;CgTfda7TzHYvRWh_kND&vk1(B3#21QIGTm1f?f^9p$P%glk0@Uax~R`TfgKaX3t5#ArE`EW%Lh;xr>l~ATf6na=uH<-G`jl z63bnR+9QO$TS3lKDVMiboR1RMxLlnX!|txhP4eX2HBC_%yD3>SnHCYlrLBmn@#0L` z2CUjoPo|vff}}YvcJB||1Swbj!I?yTRX^Nbhz>6&8O!@B_!D0L(mwCk6b^aiJ?E2C zpX;lnNI6&{EtA+{WnS3U*VI}9@lM2^TZdSs<4LLFy$;?(gN{zexDBq$B*?<{>B^6H(+03?&2v|9U<|2gEU z|G4`f0#^R0!5`lPR{cRayGr?|hEoLRr&>>VQ_u46o1Bj~$ocETw;(_7n%JXrG5>E> zT??!uv;ixB(lK9l`s7?)9t2kYUxoS57myzS-t3JR<$pF!zeaomSozaj_{Vbr{a1h$ zvAiDy@K1o}U&pr^S^r-IZEGPGA4z;ywP_|JVlyQT<>Iis>Jz#d^~`!_kBZY{}y20 zDK;SPj(0%b2J9cN9l(6=BT@g40`fSpfBdt+yth2;=@)?&>4<#6r_c6%B_Myvhgsk6 z0ju?QE_S#-49I^Hz+z=jvEV+!bte)l@&4w$#Nk}W17)gfB@Uu1qfzhwS_+ARvpSj+ zOOj%V^Wm7YY0eZ0+>#g%S>}UASN6j(oP}Xjx9IeAbwv|+me|^~-Dusiqth@1oBzrQMK4kGBgV#CJRO5w2#)vxxZfPtBb+^)8bySMxb|7nPd*ilE z#-_GrG(@&a#itp|L^q=pcrQx+Z1M@rpVDO~lWEJ~?U;NHlMhsW75V(-Pm!-){uK9Z%%33N$NVXi z?`i%-4E|IV9D=T8YdoAHWsx;R!avv!D$&=5M{>1+VGYzcB literal 0 HcmV?d00001 diff --git a/bin/brcm_patchram_plus b/bin/brcm_patchram_plus index f5e09972bda401aed07ebbb9ac766014766b7911..06dd618886be403a567772a5dc51415fea091653 100644 GIT binary patch literal 20238 zcmeHve{|GEmT!H#J0!sX4MYt|)UOhi8Ilk%N)XVHKmY~8KwM`W-*!6Popejm-F9~{ zA&kQ+GwZtS2qWub)R}Q+Js#b|aTrHtolzIgjL+vd%sV)+=Q+yk%ecDon~?R$`J2vJgF$y@|FW{;C6pk&{AP%=w~C<>f*H`{>MLoV|S;LPlg zYMD_ukR{3>i<$k|N*Yne?2_3FhT98;pj@`2R+ON<1nta2z?s>ubzBQ3YayF?De9SZ z+m}8{1%Y0a*x!phr#sRyr#o2F9f|h#)%X)V;m+D*to9~$AP>?|$K`A8!e7`AnSE_! zwwEH)25g_WYFXK@@7~q?owqv{bsqM9Iy6S$mq^NFdofk?JL<)8YPa~)lEyqJ0s5|vy z;+QFuiM*)~6YZjHMR_*zub+6lvSYXZnFs#&Q=8|#k)HNK$C1^Ket5ca?cV3TUpqB* z%54umvAONQ#D|lMc5bd+v-sTYpJrbB(|5NXs_K1cQp50HR<7GN>sm4M(`R2lz5VT5 zCw=25cOQDr^UU{OnDUb!rl(CEczW}-b3eZGmDw9EZ(RM|&E@-xckGT&{!!ta)RZfa zZybgAF$qg4n`}U|u}+-ZPK}@>{>wa^D7;Ro~Zr}FT>0$ypzyCtvv zhCKXNd3Zbze=iT`TGWa9Zq^7&;y=p61>!}35#kn+OeF&Gei7=6q(m&9ibR8~N(90Q z;qyh3vA}`_zGO1sk9LZ9Zz{<@fv`Uz{2j4GN(4HSp;ROp4~2pt4sz1?%njrd%NGy=*7Rml(D%2x-lii^Z zx;&7Gq(Z`KY5%3yWLZ7895gS*qL=arX5&?KE zO9YWNmI%CGW{CiJFG~dGc9saXL6#GQ2(yIKcC$pljTXcRTp919C^ zqG-$OM?HfzA9)79|Iy^Z#|Ddr{{ExGv!KwMk9{!h?QI_%KL6TB8a`maZy4}v2K=%C z?>69P4ftsT-f6(w40x*nZ#LkR0e2g4(17nX;5GwZWxz`fc##3u8*sG&R~c}n0hbzZ zi2-{IcqE;(;U|Dwhs0&blU=Xf*W!8EdinpH_wHYP-t!yx3eTOH^rL4o=?~6aJJS-s zyVeqafa8|degC6U`}-fc>mD0)*^hrL#JYdFIy1-Gm&qKjztIv~;O9kq3sw}|Sy4V= zws^PbbJpIR>JKaCtwfyy?MU9#Cp?zXs5%*_E z+xLEBkN8nvdtbP9sMgA)yU(0&zYrF)z3(&+m)*2~*yXMWm$ftv*UjBOY+0ManRMNm z)*-jZq;EKLA?!YDxi7Rg4X>(0tN0YHhflj((EH$cy{DnK2fd5VP@;guk<+f0=HYGA zDXY9)LlxnloXy-`n$@Bbyu}%JOGVg*Hfyum96#MUQ~-X1D22PMrSNQN;p;8iU*EF# zAvvxE?E@H%>)=BCos#8N5pEjplRCE!Syt=Nm99+sq0<$E3o#ds-b)L^T{vJVz7C5NRI8Z@cQ%f?1Au; zO_QL<&@_zKbpeuo={{6;PZ(U#!*Ul5YO7udPntdWJ9AW9UW+f+Kj%CQ%8l+5GP3!+X#G5U9zqQ8$pC~+A;&z`c zb*a+pMrm2dVuyl?EX#pBmPrF0-s( zm#sfvx#)Km{Y}xzh9@oFY9`uQW&X}rB zz2bj0;&H}Qg)ueejp>5FbnrriW4aJgdf9SJWpYgKI(m@;vB!_n858xgm0sC-Uz*38 zG=_gTF@kGpr4jcx&)`2?!w>$8?fa4DQCxD-J;I)9?aNs)tk2vsBz_ZpWS=3>z z12+J^*Ma8&-sZs7fOk9a4S-j}jyv#iz)w5yhky?_@IM09`oDXk>6}L>KEDOr;J^m}haLD$z`GoH zKj7yb_~(F+IPlAWM;!P?!1Z3m^LfBw2mT@8Z4Uf2;O8Cqi4(clxM%OTrN29|Jx`Efadk((3fmf>F?As5vU|lpwU!(`#aPYIR?$LVOHSMV~T))okmm1D!$)sH; znuja1)Qt5SYdUuzOLh8q>(E4aWB3HGI*h}Ou0x2!b=5igvX<@3&j%)DrK|W`fa@Z! zDw*`wQL*m=wA_K~sj3+mC9WdWR`m0#6%^)mZqs|_D6Yuv3Cb}VMOPs;SrGm;M&xb5 zj7^1gta3;iJwBG^*6<e@@MyBzjd6e^^xhcAy=z{)SjU{dzHT`PY!u-A93V3 z_Yt!o??Wl?I>>v|kcY^E8FEGf?&g@h7?Y{H(yMuRZ5?zGoQ;jJvx*drh(>$3C)m5y z*^4NDxB=IAF?;esTz%@9 z*gZVibohPUBgf^@<6K@g9m45jW?l1e+x-{`>K}v#ZAn@fTH`8g zV)u-}p3GuTg_}S5AM2Wiron!yZ?278-Xmq4mRcfZcqzlce?CSR^svyL06q3+Z{)R6 z$L+^3D(v-?eX+B2R$E_q+3*!h=tti>Mw>J4D=S=@_DV_nNFJ@)8?*nb(A)90Ft7aH zmSw|LvQP9F_g7Ql6>7HVU%OE!_o?R=WoPS&W4{_SSHmP@HM}Z)KbWQ6BJ~&;Bhw>g z&Xh9iFCjCLmANI$=iXzFjgdJyE0gi#c^jT2u)?wbt%QADS^JjfjdA4Y#bdlRD=#<3 zs$+MLk$3SJ-^%JXIV(-Yk*hLTLn?;#iP<+n(_H);tM`Y7-lfp{xubgZWzugSJrAqp zdb-}>N-HtOjeD7MBT|dcFjH?I&D}3t%7-qO_TGGyE7itIy&Wqx$Gy_v+jP#02%zmb z8G7Awv}CYp*c;EJJ0PXRO`lZ!+K%$tpn0DBoUz&l&jRqQ1E;Zm%)QIkN5}H7f<B)|5XzyR`nSgzzT6z4t(BC=~lxw?4+OY!jGMe6V=GE|ke;|T;=zn>9i#cX7 z^bO!@EcEp+8+N?HHJaXbCNh{`OPyw4-Z71Y$_cyD;Ilm+|he9 z{k+s-q1=xy^xqn}fLOd7u{bva3$rsYBiuZER9>|z`pR(yQ}9>&DzorYec#K%@AqAu zg)926%EDjm=N+Ev`&9pL&Wl0o3D;k{w|gEh!hEKrW;0=*dvULAxvzq+(cfMTPnf+G zcUC#Q#;&WezBZcvEPF>?iR;G@u48&$)c$7xbK=I#&;wr?<=>g=UK4i-miwK-O|ZnF zvH@w4L*)zo)L|fUYxuWi3nP8usV$trzde1v9ak^d`{VaD{X%)qUD3DDUw9FZ{Qi$- z`yU%)@lx!V1|o;bE+86cFW}05UfSlf@M!vfoo)#8dBxn32F}S;Uh`Uq3gH{w@(D)l zKXuMt$oh%qOTz=&f=L(-#1$bVSm{-K|**4*;gPTJRa@yNC*!W z`?7wq)3cp^F(_q>rq^O#UB>;4nq7TAvj7%TS2`7!lYcZlW?I%NTvbJlxrkQ;%YAT) zd)!R=&o5{mGt=4-IK-2@5jzE zi`{d-rb3i(J$XNOJLdfvW5+-{J+FCqyO;Y8$i}|m5nOF@qr@Hqw&8x_Tcf8cwVl@5CDay#*H5S5B8Y{!-+tEH&x8~uUhDNuK zqtUX_=3#Xg%R2!+Il5SH%qKMQoLYL$ZXZp5@l?$qMkM1nbd#1=*!z9lQ#eoButWE@ zd~qdb=IBX|*W*Sn#7VV_O+)U*k}~N(!XFd|`bWh|!~n>C^Q61QJ^Pm!vwG4(U9SR` z+uMz%51br}PdjBwz)WTLdRUz&GwG`{Ig5#XU&gb{yO7l$)_LX?UNyWwuz$G5{bbX0 z%+jD^&jQTke;-Hx??V4w4&6l1Jv;ZM9WHJ;>tmizQ)4K3@&(ejo*%4d#}evd=%#i+{0p}*Ro=lvtsLow*ZIP?=> z1>Qkwx|6_jql8_Ybu&DY)8k!-z6g8|k3;{Sq~E@m&*xfk542ET>*<~2*=dDgrx~!* zZrt-KO%P*RxF6@+8>msw zQz@5x4xvUpanv;*phi8f(=`Q%TXkdjl%l50scAa*h%s-IF>eQXcZ~5Aoe=wKj-78V zY$;juNK47;9W4(o#lGzL*OqRq_^Ef|LC<1QW!2wx-gA3H%aWEmT6Qgex#`?HuOB`C zu-G?kk|m0e`HYwE#rRH)Crdgb-68w>q#cc=Y=6{V(Y(}Vl{}&l4g|C9fmm;MP*Qb- zY`#4W1*>hmag8PH>w})uckxm zO29|0o%*299}Fh!4poMdNmU<;`a8NqzV3L>7(5(^D7-fr@@byF&RD`1j6D$Tj`^Wr zjeS=#l(bXf5XMqmtf_2J*_tX6?IHo}p6GeNp9o1ElYv+~(6bnYFA?j-i}kK*;6A*s z4kbGMfsj|Op zMIt?+R5%t?4bk47>O`a~obuh*n@mMI`)>o!iN(ctheJ?G!G=C|Bx%>lfvjy_U2V^m zU|Yf;O>*v)KJ#Q{GZYHIyMp#j5??uQJ)6n<;xXme&YjnAXHz`sum*i`@w}UFu~nVo zeDmCS3RR5f*3GMzIB6-bUdo$SSKn}F2RJF2IiuxdCBx8Js;I`ncl=Vv;^M4L4eDyjLIqCsyckn7QK=ZZ~w zG0eT?&hRFRleSbITW^y<%2R$KgJyOq(dTmv;O-KWw%!O1|5A?Mtzs+}m~Ml?3B zqd$d^liU!AC+!FP5ylSb5vd1aHrwn#EXr7;j@d}vIzk9YAzPkxA-N8k*%(!8uL(VX zNezU-mG&ww4#s4x@4}@(jsczspVdN=wJJ8IV)78q;+{w#5yOd{STu;JivGPkRuc?u zj3Aap5yenPJMj=vEQ%lx*nS|A3fnl{qfmj%l)Nr6zMu-@`21^9Xrd)9$E(+V+WJ@fVVhKMoE>C?nPZy^09FeGGxPF0+BdDd8LcS?8WL@w>AN_ zW4%d(LN_@)aB}Hi;juIZ2_TcRlNBeW$uTzfCK91&>QW*gqZ>WCu;L>rI~hns;wjl@ zy#(zS_G^EmNyp1l*F-1~iflwTxqA>|SzkO9z>dKluNUjlb6sF#&}RBq z=y>J}Hj=W|#9)(ncRxcBjDxue#1O)w+_#LG2Yq=){rXEzjU2Ku$Jhd30}@Nc01c>DX0HR|7C&yZ!EA3F~0_xiGP_(m~q^M=dG)7=8Wg7dDb3BAmtfkp0)M>=Q(ja z8I*aaWr_bgnu!HnmOQr|EU@JH^ES67&u>?QG0#2o{3XwBGvWE77y%!i5<7~_Gv)f6 zc~zk$VGl~4skM=L#vI2Q#b_oIJ3IlW9#B%>A(Y#J|9caE8=zAe#`~Y0wQQCci%gcg zL|C;W!YUiV16GwR%Ybhj!SNrNWTRC%Qjn#)+JJjTI5omrHiDVK98H#}5Wm1(EGJ>B zTew*k6$%eZ`v--hfcV=*VggI=WKoE+v1y7ZBEEB~C`Q@-PgjVED7S3AT3m+mnd@&5 zB`Ej5StBN)9PGMTOhze+7mFzTA}nt7 z3+C4>5fdgBE-A8#T@yXiJkzaG>vHQ#cbPTADtA@5E3NA+=vJHT?@9SPP^J>93~NZ< zyT(N=9yNq&mo%-cN%^}RtSj1E+tC}rZ%`sZQA;fB$0_aFV1E?+REdM&vSni^k>vSs z6Y-%f5$Yzr0^;2%QOo_2s7;0X@V65PnqonJ$}eh{tXo}+GwZ=VQ5y>T=)O0HVbFon_NW!e!Bo`e!QMl!7-?}PMYp}s30BfQVqIl&<%26PSSMG0S8_DA(ZMjaEhP) zZIq__v7(dwN)dNTYjQe~rKWooF#B?j)o3$#%%35HS6o)&&kE4Z*9c0j z!c@SNsngd%=WKmsm8N4!AJ8edK#2Wt)T>c(FEUm2BGWZYepM|(95)VDx`y;pG`CRv^T{$?{ zx5DKupj^iaXM|GgRpDyIa$PE%D_mghXS)a6NvmWVSOds5DjLyR$z6RPEXx^d!=2{rC&dwN6hK zl=mH!uNeKGHgK0C@37HMdd63kN(6B|AB-R`I4vwR|I$4ASB0Q$c||L)u&W6Yo0iMuWx?r6vERM*j!V&if=L&HrAbo%5&tm3JwRlGO1(3pm>; zU!@u11;t9D+MgaV#z*=pgPwR@c0RmPzhIvHREcIfS+@5X_}`C(YSyms_-!|}kf1&<*ee)NRN5D$syt`w&_9xyQ9!I;z z>0f4|KIhP`=Zp3(glYBqx3K=bG__-Yw$B8vKP&71lVp3ffiFOR z{`QJ&r(wOV1hCfeC;lGyE;cyHMtMJQy`F8@d$ZBbd)aRR*YU@T{!iz%@6N;b0bd1q zjQo`M7H~eJ<$i_w`~&d)@E=Cb{mx+G?zRkc#fp4FWKS-2cj7!WHY}|_g zC%+lMkAj~20P?#A_>QTTxCLF@f0?)$_yI$HEAUV8W6LKnPo)2Ez?T~OcLLXm z_UHqC73hxuCjCReb-bE}`11&G%G2Y261b`VbHE#n_T9kw%-ZY7{~7R}D=q2&I23~LUKMhgR!AJ{#wLiT$Tj5htkCe~R^| z?fDtz%NJt4;}pPfb-e?4G#Vm@J3^N2Y|ne@pG%f@t*>| z$Y}or_@Chiu_qn-d9cOUQI7d>@F~FCK+g%GKVAX+F3?vy@@(MR|GnT}16(KCYccSh zkdN+C{#|+Pi9CF(f!pZwxPg=3-vIvu{P#Ry+T$m{_4Q(^t4!?Aqdy4z3x>Y$0q6Bt z>Ejj0fbW5R+^Nt$qj~+Osx1~;DG#v&INyzEd(Q{X-)J_<_Q_&-9(^DWe-OCo&kyId zKLMQYVQz5v{S^4(%Pg_c!4ClE_d1w3{zJfrpnn`V_5VlUI#J&_J5_Em*?$f3tH95}?*;x{@W)YR+1>%X z4e^Nb=uh_n=liBz4!;!e?S{WR2>dIUZ{8P^|D(Wl;`qLshrejxHrjsyoYz-1-!sG^ z;6FCv-x1)|M*GLW7ejyUyC`oMcu%Dz@BN8qfb)IX4Nkk)xCfve1hjreBc%CoP!5tb82gy|Cb^NBvNy0W1=c3 zs#5>_067XiH6^F0vqZ}4?S|6>?O!5Hc$Q@x#?wE=vy;Ev{XzEvyNxA}Ym-%JQ~ zMff`1m+JB1g>)28t}apK!;uzWS9h$#-|Y*gVu_^B-`gkf=nHS)@zSog;pPQ(;Cu-p zoIHs})RQ#4!cQgog*tu_?Ct5{2NVnphg%}4F{B*{9C^`i&U|rvxd8)EpI?x#iIcUr z)Hf^;q3+Ha_N|Sr2gjCmOI9!QEnBk`<5Ppx@EHF1;>6OgtXZ;pWizOZ7Wocb_?E9~ zZCbL**V@vuep#EZZAsIrWn?Em2@y#4%3jw}n3Wp$i|+ z=s4$UgnY~18ANLkhcH4ufKps28iaZ9>N4OQtl;S;%>4bq`9iS`^aL^5Xh`@%@@Z#| zKY7a$;axBe5ulep=;MoD;PZ1YBGm^wOvNQ(9Is-9GN1Zjh)JPrp_G#cx*TPkH=PvX z3*a*%Ic1!)TA%Zt6px<+>RTbEBsECwTk1cbxQt&cw89%(u(KHFj{MuGa|ny&{7Cz!x{e17gF?{g_;C-p%VvnKD; zDLheVHk;~ls8A^x^M&!w9?OYen=y%(B$J^;N@~8c6)PziiTZf>$uN#Qgd&f_>94++ z42LLwWK^IAMiOA}f+Y1_6^X^pvYT|MN8_jT)*xIADY%Awwg>h`=$k2pl7K9zn>j z;>fAWE~H+b(G<9#^h9F#+>eY<+E3-#3+2?#f`;GoTS2BK@&i9+h3}4yzID!3s=3>b zxlU^S*;AK_DdiaFD5PRaCY?4(D1Ca3=g D+r0Eo literal 16943 zcmcgzdwA5vxt`4iNFtYjQJ0JMhoVMFV!(*uVud9vgo~koE%s42o83)zVY9p4-9RAN zBGOi?wzOhvmA3Xg)ap65;)Pa^QmM7p$J+B?;XL)yp5|D!5m7=On?!=y^S*Q0okZg4 z`R5Ew=6h$p`R1E%uKSyruPj;VbGcl?xB^iwh<<&$5H$$fFBPIdh*34d5k*M*jF`ss zq__x)4=7)RfWA=s(FmEhX1nrIATo{8>29V0*W9f9WMF#cN3`?^gxIe9Sd>N2{EQ=y zigO`!iBbsMHAV=Q%XH`~JmB{rjlLh4p6M)uel>)wM)~x0!1N~Vb8lxtfS+(C|7Edg z(`B(xWh@$RYp)EXS|iO>=|t7#%s?5X@YHeXHP_;=(uaAcz%#uJo;G0mtiP4)`?6E8 z;ZG-TDI4?Xz&lmHymIMx7^?y08+QhXnedK|C`WjSrdjU! z@Ff~cn}R+Eej+?|qx%f}dGM?Y-MR47B&Gha9>o?u9f>9x;ygg(;b{lkvG3S!k_|LX zn_LV(0iNwU6@DE2+3?1ptBM)$>`QcK!80H0Z2IW!JH2BkHjaPc((b1g6;&UpMv@p8 z9rXi9b$Mnile~&hax}KW3@vKFwez0xcxUW8b*)>=7 z*7n>!?PtmHk6isx_8Di^-&fr9{=^9fKG^lr?C1L?U3dI@Tdw}{cehPFSp4nYw@P1G zdq?^7H-GlR)TW06_h0*R$t^$r(L)m+|Chc=uYPI$v@w@uCj9%~zO(If`yVX*!r=!B z(+hTQyY}bBbG=Lc^Vs8+=S+C0>CdZv_4*g4mUisf_SBsx#&24;VD~vkHx1gllV;yF z&H-WS$~fXP(Rn?XW9VqJpTRG)a6Rz*Xcf9iu<#k+-}w!Lh3Ej@Q;9!trQ$?(GRT;f z{vzVrEqoaGK?~0T|0xTEe*srm z`Zc2bX~1-}?;jBEvhsfuNw)q1IA*0gz)x6sH2E#O0P;Ti9_oZ}5=PN=NVm)DLHr&| zzhy{oxAJeLJgfb`3I1-2e-7}X93CrT!{ld?elV8~fH}P>))vkr5}Ama&HetC)IG&3tp3kK5RU~7`) z2U0DF2_d71CW4um2*j{*iMDhs98QYn&8cW6ECQKC6vCQgZRrRyh2s#FipDd|h-}d% zNJSDx5mr>2s5KCc3vi(@XclkrC*rX!!XFL=G6AUEluj!~o2Ff53e87ahX};dmG$1m z{@GPm<|u9|q$|K0;L@J7`RCRY(}w@E`CT%%kzrCAAls~W=R~7eUfkj?^c%*NNn9X) z08F>*VwX4zG{tehaO%T8pl>=yHp8EZSqyr50Ue(ZZtp z2l965w&*U4?zHGvE&34XhHh~N{P-LC3#V@It?DnVgdg|U{<4Dz|4_KBa7DK7j^o+B z&f`M7i}m!^Xp^5Hbgw8}-cfho`ZFHQ_TBt!a%m|RuLD zXCCZvxu-^^`09K6*BZ>ImNkMye1z1o zkOB#ZK25@BA)ycwYL2sPfwC_>Uf}cg+@EHdQyL95HS+k0?A2#m+MEk*JRy`-nC&Y^ zNmC=`zUfk{GRPbSnI#B?+v6K^qIApw-@XIl*+q1(MR(r|QA(;pw3k|Zur*lVy$;q!?* zBCkI-KQbjb=EPW(zU#pDC%&r7rd9)uQ#-vqr(`WpM%MPvb~+;WddIzjxD<65Ksmp0 zANG7P0vV0a#a+~CY&;MdH?#9KQ@1im-~LQ;>Gu6QbQ@;-Uittw?7d#L8*HelsSyui zYbHWI?EK3tTjvb4j^bnL==yA5YnGB-oh*~KE24bZ?lH^}yY_!;Um^O*mPmc?dTBG% zuAtyVSph;JPLvj^5cDoZ6$zK73PpjW+`EdgyF0EC;1kBD&MaC-`iKDZPTu8Qv|zUxj0b>yD)@@4M>fZb|FNLeDht<2 z3s*}EA4zkh!NTBxg@YX%3t?f|GQqQR`P?T)xj&h=^E7$imU-E87RdJ4wg2{g1==q6 z{8M%@{lkm8Jso&DTBz$b19e+HtZoB=vd)1h>oyQo`Z=<09$B|zT0e4Nb_yWWb)$YW zhV_?q!(@}k>Mz##n({u!*Lum%@ujG#oKybHR^aGSeNv4cGdAmc_eu+Rd|NO--gvCO zcb}Xsvwio1ep%DIL3e5To1jIKGitW)R?r?z?*Lt{>208EHN6RRNYhEscW8P8=;t*Z z0^P0Y8;>pT@dzbhd7U9IVN zKsRc-6LeD3uY=yJ=_8<@*YtmYKBegwL02zSGM@vzPSekTPHOrW@0l61d;eXs-_Mov z(?D=}&ymH*i}`JA;kmvEf0*z*{oP$|u@hc&if6sOj_gtFN24$=8>Hsqr-STMPd7q7 zHnQ!Jxsl~PJH3!t;O&jMIfk=+&%EdMaRhU%^dIWj$TcoB(|f2MBWGDocKM;@J-13- zo{AuE0oR*`qppc-Jd>~nOvKDQ={;|6MUH2?+q(vC3=C$jQ zTiIhuge&Em*Xh$1IBVnr4bzbDKhvheXc=MOCeIFd< zu47M{cI2)@QEJyQ&DwRG=Ud+Ma2>2(_(^H!Vobkzlsl1X>_jd_%?`mnY96S=T+@AE z`+o6AUN-j_1z3rjkJ@qG-p0>C3&i(8S1v<|C(WG)Xj66xbZo?7WI(lykYo@!}8c=I7hjc*sk}RdTcaajJ=JR zIsOoKINcN6VrH>rarUsuuqCACcA}Hf3a4aypNzCec6cVWbIqW(W{-3d`=)!nhu_HO zF>>Y{Rr^7u$JeYqSw{f7S@-@Dq)$-a3}%){?;cZ?FE z_j=!b!|t5bdh?ZBo?vv%GUw@bwncJh>wA|oNw#lJ*6xE_BJ&XU&3D!MhrO#_`@B7S zlkAV!v!mUg$4-%Z_etP0>zsI`p?kcj@4e0ijlnb6H8jt^>OB33H)D*u(nh^2ox|NH zWOj9__Tiq^+w-7R>TN?b&F7q)_4cY2obxAl(w~%%F@SOLV3)mO&%sP<)^E;6FLhO7 zu4z1zV@=LfNrT>K@34N4czl=E^Ec3rt`7VXD8#Ra#!}jb{qV{Wbo`y1)x7%G4QHPz z_2_fZ>BcVZ#-BsKSG!Tx;aq5@#=jb88=$w19~ff8p<_SRmF=rV|4{7`!f(F-{5_n1 z%YT5u{> z7^O4qQi2+sF5deoH7P=#{MyBt-Wjn^pN&2}*!Sn-_sBVhJ?BYF+t>)&p88nzHS%+h z#Qt51+N~Rb|1FFEh~_T_|AGEHw>^eH-FiP z!M^j4=e0uY>ln?5_27HR+EdxSUw>?mog$1K)6>LE*CBitffdzP1&%G(U$8nO$55UG z`mOq9DS43V&xldKBTdYEh*7_=Ow38dsNW?f=3LB03(w>XVqz-fyf)Z(@Po>C`xlS) zjaxOr_t*ZKUAufY)eZJ79{i~8x9=4f`;R_UTzp8(xVFD=ezk9|&+Bv5+_QA$lHOMi zboJjNo?UmV5NqK1`xW2n-1ov zEf$hoO<{*$gu|f<2Op6WDd)lvxV?e4P%4lKOO|w7GKp{1;m~w(VfF0w^G5oEGA;~N zjQoFSy0|tSXrZ$6P+swZ%Ft(>Ou~`hrJaBi3OBX2II%>FOsh-=@X>VLPpx%)$R7xWQcjZ!!|Ak&561&dv9LduY#oB}xnJS7bl7iX`kNCee<-mz z9!mtEV5M^{&Ig=Kgy%@b#fHlPmt(l1@fI?`?y1(zfmB%Pm<}eA!Pct~_*02CoEo%L z0OOnirw+}5U|6bM(To~~{h2MvaD|kg-VzV`TN9yhMG$8K8xP(nk&3oNGX4#1=}feF%V#08q`3GCkua1}w55*|O*_@HBC8j# zs&HmWa$PDAPqXcnKC@-yVki_u?+Q7WOI$yDEt4txlXc3Aoi)35g*TbjqQPHWJo}0{ zj*3%~ub4GkK_z%r_3Rpn$;8s#zASBC- zrv2J>=|F1|qmsi{_jWasWjXmA`9ea`G(}j|)iPOE=#~?m&ypUop}}t{kk3)OV%b(R z7-r2`5!uS(q%BpCt#Qa8%TxVCPMW!)#6F)FfbK4l?A>e+c5n)ib;x&aMpc!_c_W^f z-LxfxDJQ)#noK*J15wT$vPWb#Cmg0Z!9<*MjXE-vx;2F{A%z`z#7TBDY3AmrD(9N; zW;ALr0;#lDad9Xi=lT{b1+ot4iRiPYkaU%r8#4)cuy|E#G?+@@5Hb-DVOB-{HlC)2 z!keO)%i@^D5Jx-lgftPyBoErz9L+==99SwSuuREyiSrAhP>)Yvljhzb#K(6E5x}AF zsBZ~zEqo>XP4IW`65@()3vmNHmZx?H<)y;GaC8&;yIj$5-vVc$u!bzNE)j=)!Wn5z zGmRr^C26%T ziTrvb42=Q=&TvOqhmcvVCqiIg2-8O>Q@4*e_;&Uy>O=>3Qed}<@N|qbz5(=Dc%G-@ zNKoF(;2j&@z2dzV94E>c1=LQ7`yWn|`hWBc4^eNWgrs!IPIC2#Z{F(6h5-tX_*+dcIvk0ko zH^P0`_xxWS?~56?67~K6_NHuxsEc$iH@^K>of0n3DVk3@m&>9rJ~bA1_~=yHv{R!r zn{b_H(XFT0EW)+ql;V62cIM&sPB%UkAS@aq3K2R#9wSB(zf>efGb|l1#vokiogj*c zcTW_>2pj))wkSckedl@N421Vzc##;3@ZbxTVjRNGmMg?~grfK=F#+KnKT&-OG1A>L z4DTI=9|pGFlf&@y!*J)Y{9VKFv0?oE!_w`tNH1Nyc%D;U7jBAThg?%Nr|R;`Sv8j^ zN-UZUjzBoj6cw&=kfW}wTqH)9j9FCVDlRA~oK#rmI?HvA+vA$-no=;;J@Ff zt(ia*!c0nq5ktuhUQ$$HKOU}HQ!Tthz2bDba}r{TK>>747x$N6s=G9Lt>E?}3kI8;6l&pD8M zoG&pXHJG2wI0H;#OCsA7&!&b465 zm`WmzeDvS3_zvC<+rgL>Tm-Z;^6mjPp)h+_e0G`yL`*VWPy z_zr`IpGNB<7I;oA+q z-Qc^G5!#W5?if7fQa|36nsy297MVnyhCrNvXLj~YI`W}Oa*k>AC*dJ0X%gmw?{WhW z8Wp%_V423nz*k}t5ot(Q_6g{Oj>MQaRNgjTYv79xHc=eF*W|MC#+Y zSF@u%**?xNyf;^#>Q9{(CV!WORgYHkOnuDw;jf@SAjx1CFzaL5moE_BurS;E@4%)# zXwQCNGoEmxQ}Bm@u`kohfX(=Fp*QhfI@f9C#>w)ow=mNiEzJ59<@)d4-$z z5;+s{9{5#Oe$EbSfX(=EVBZ^nV_H7b`D4$%H+~baeeeHH;GGu#{lM3w{izr4`9B2A z?*w~w`M&@@g8sspaw5um8JPV?@q5G(;QKB7SEgI{(2oLNb)OJbTHZotN^y(72E)9>k|cDX65Hb(7so{9r!wIn##4l zw*vD!3Ew+V-@AdIggzzO9zO-Hv*i66*nU^>Ct!Ymc}L582iShc@G-Fc&H`umL+;^E z2Y%UVui3!%JBK>pah82o1HWbQhk+mZt`J|-+kjVF^|=%H z80yPC3)}zaz$>lv{lK%nC&Y_7|3TnJq_cytKm88a^w(14KLTvOOLzGK1^x%>{}R&JKKvbF=I@CG9&s)33_ZR$KEl9Uj}Sn=Qjr1iJj&|2Qzeml=CK2h97!b-MgN0^9F)J^;4g#S~-9V)w`K!1lYC>A?Ip zXXGyeo_;6xh+6&^fcX}Yj`h6}_!RU{0#pAeu>J02E3jSO4q*G;$Pa<}?QemW_b{+M z9-jpM@!i-f>;C^7@DHF*qvk&X%sbR?Y5W@SD;PhkHUHm%zYqBzYWzNMBjyK|$NupT zV19$VU+2#P@3s0v@n|7h(Z2j0$oifIyfasS^ao)39nM@};~WsHfVsY*8Dx1k0{_+; zFD<|etn?J{&CvfE@Uy&|fbDlV-vH(})QfcbeZYGxef|x2p(XDZzz?H7C9-^v_&qSc z#fEhL*MZkt{BHu=?~XnMw%<{W!UoBH$8!d7t(E^A;15wA%qaWAJYf6Xk(dz@Gw^yQ zfD^F%a~=^)Wzw0p=H{v(-kdC7yvDz>e(gH>040?0x5N@nftWv(Nu<*LKwG=OXAB%U z;9RrniaD2Gi5#b4lJ9=hR}q|9WKvs%I&TWKwYK6FjQWn^mq@-E8p7I?!Wp0W{OeER z`3)3PZ)oIq@pRSY)t6rZDZVv}RxR-_xu#C)O2rM$?>RY{cp_AH-8G9=)h|XKD@A_j z7yhLy8@!8F`Wt+{wM*9d*Ddm{T;dlq_((@S=Lx3U)GMakJEesS&10Mz!OuJTA&+_+ zWG7nBe4t?pkCE(D{j$i8%6;cf22%Wt9pXu>d{HG|B>8#ps1FN;JUVC&@q8L5OJP4q z>+KM}vj_EQ5sz%~HJt+SBny>_hs`@A^}x#3fUmbySu97^4u>K*CCPs;SJqIExa_R< z(GDK`Fo44uAY- zXC3yOFrS1;i%;tGlfry_jc%xskC41;7Oz6yAkOmTWe0iiD)a=v(JLd;^3W`73pQ{0 zhQA23c~n)+S(G(-2svqSzzdvmN74BCBQ7By8p;OB4S+UY5fM0yZ;dAKa#9X`)8kS& zpUkN4smCA26yIUmn#d=UcEstPdusW)OCL%o%dw8;q++T}cFf$vP^FZ`$j6p;iPm6Y z# /dev/$PORT # pull down RTS on UART log_action_begin_msg "Start pushing firmware to device and waiting max. 60sec to complete" From afce32bb996c8fb875098cb744c70b093c809ef5 Mon Sep 17 00:00:00 2001 From: Thomas Kaiser Date: Sun, 28 Feb 2016 18:56:15 +0100 Subject: [PATCH 03/15] Re-enabled all USB ports on OPi One/Lite since available for soldering --- config/orangepilite.fex | 2 +- config/orangepione.fex | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/orangepilite.fex b/config/orangepilite.fex index 3d0e85028e..fd89ab84cc 100644 --- a/config/orangepilite.fex +++ b/config/orangepilite.fex @@ -541,7 +541,7 @@ usb_regulator_vol = 0 usb_not_suspend = 0 [usbc3] -usb_used = 0 +usb_used = 1 usb_drv_vbus_gpio = usb_restrict_gpio = usb_host_init_state = 1 diff --git a/config/orangepione.fex b/config/orangepione.fex index 7ecdc3acad..94c2c488c8 100644 --- a/config/orangepione.fex +++ b/config/orangepione.fex @@ -531,7 +531,7 @@ usb_regulator_vol = 0 usb_not_suspend = 0 [usbc2] -usb_used = 0 +usb_used = 1 usb_drv_vbus_gpio = usb_restrict_gpio = usb_host_init_state = 1 @@ -541,7 +541,7 @@ usb_regulator_vol = 0 usb_not_suspend = 0 [usbc3] -usb_used = 0 +usb_used = 1 usb_drv_vbus_gpio = usb_restrict_gpio = usb_host_init_state = 1 From 04ad1ccf8915c15e36b3918e64eaa43d1166dd7d Mon Sep 17 00:00:00 2001 From: Igor Pecovnik Date: Sun, 28 Feb 2016 19:40:01 +0100 Subject: [PATCH 04/15] We need this util to reset BT @Cubietruck --- makeboarddeb.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/makeboarddeb.sh b/makeboarddeb.sh index e80a9fe2e3..0b1bfa9d67 100644 --- a/makeboarddeb.sh +++ b/makeboarddeb.sh @@ -122,6 +122,7 @@ create_board_package (){ cp -p "$destination/boot/bin/orangepi2.bin" "$destination/boot/bin/orangepih3.bin" # bluetooth device enabler - for cubietruck + install -m 755 $SRC/lib/bin/brcm_bt_reset $destination/usr/local/bin install -m 755 $SRC/lib/bin/brcm_patchram_plus $destination/usr/local/bin install $SRC/lib/scripts/brcm40183 $destination/etc/default install -m 755 $SRC/lib/scripts/brcm40183-patch $destination/etc/init.d From 36a672fc789f4863d4c6e0bfe321aa207040ba3e Mon Sep 17 00:00:00 2001 From: Igor Pecovnik Date: Sun, 28 Feb 2016 20:58:26 +0100 Subject: [PATCH 05/15] Logbook update --- documentation/logbook.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/documentation/logbook.md b/documentation/logbook.md index 03b6d72822..05c8dd1ec1 100644 --- a/documentation/logbook.md +++ b/documentation/logbook.md @@ -1,11 +1,12 @@ # Release history -**v5.04 / 27.2.2016** -- added desktop images for H3 based boards - -**v5.04 / 26.2.2016** +**v5.04 / 28.2.2016** - H3 images rebuilded +- added desktop images for H3 based boards +- rebuilded Cubieboard 1 & 2 with 3.4.110 and 4.4.3 +- fixed Bluetooth on Cubietruck + rebuild with 3.4.110 and 4.4.3 +- all new images has no login policy: forced user generation **v5.03 / 20.2.2016** From d78dbda6a522f3c01693d8bc16dbf137c2ad794a Mon Sep 17 00:00:00 2001 From: WereCatf Date: Mon, 29 Feb 2016 10:48:45 +0200 Subject: [PATCH 06/15] Udev-rules Fix issue #194 --- desktop.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/desktop.sh b/desktop.sh index 0db439a9c7..edb7b92d06 100644 --- a/desktop.sh +++ b/desktop.sh @@ -67,6 +67,8 @@ sed "s/NODM_ENABLED=\(.*\)/NODM_ENABLED=false/g" -i $DEST/cache/sdcard/etc/defau # Compile Turbo Frame buffer for sunxi if [[ $LINUXFAMILY == *sun* && $BRANCH == "default" ]]; then + mkdir -p $DEST/cache/sdcard/etc/udev/rules.d + cp $SRC/lib/config/sunxi-udev/* $DEST/cache/sdcard/etc/udev/rules.d/ grep "CONFIG_MALI is not set" $SOURCES/$LINUXSOURCEDIR/.config 2>&1 >/dev/null local error_num=$? From ce04fa0f561cad80eccb8562016fe60bfd67ecaa Mon Sep 17 00:00:00 2001 From: Thomas Kaiser Date: Mon, 29 Feb 2016 09:53:56 +0100 Subject: [PATCH 07/15] Applied backported firmware loader patch on sun8i --- config/linux-sun8i-default.config | 2 +- ...oader.patch.disabled => 0003-backport-firmware-loader.patch} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename patch/kernel/sun8i-default/{0014-backport-firmware-loader.patch.disabled => 0003-backport-firmware-loader.patch} (100%) diff --git a/config/linux-sun8i-default.config b/config/linux-sun8i-default.config index 6d8682f810..ad7649c197 100644 --- a/config/linux-sun8i-default.config +++ b/config/linux-sun8i-default.config @@ -1185,7 +1185,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=y CONFIG_FIRMWARE_IN_KERNEL=y CONFIG_EXTRA_FIRMWARE="" -CONFIG_FW_LOADER_USER_HELPER=y +# CONFIG_FW_LOADER_USER_HELPER is not set # CONFIG_DEBUG_DRIVER is not set # CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set diff --git a/patch/kernel/sun8i-default/0014-backport-firmware-loader.patch.disabled b/patch/kernel/sun8i-default/0003-backport-firmware-loader.patch similarity index 100% rename from patch/kernel/sun8i-default/0014-backport-firmware-loader.patch.disabled rename to patch/kernel/sun8i-default/0003-backport-firmware-loader.patch From 793a95740f12efd30aaf0047627c8e113939cf51 Mon Sep 17 00:00:00 2001 From: Thomas Kaiser Date: Mon, 29 Feb 2016 10:07:19 +0100 Subject: [PATCH 08/15] H3 Mini FAQ update --- documentation/H3_mini_faq.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/documentation/H3_mini_faq.md b/documentation/H3_mini_faq.md index d039d8f8c1..028834340a 100644 --- a/documentation/H3_mini_faq.md +++ b/documentation/H3_mini_faq.md @@ -19,6 +19,11 @@ Armbian supports starting with release 5.04 all available H3 based Orange Pi boa - Full HDMI colour-range adjustable/accessible through _h3disp_ utility - already useable as stable headless/server board +***Known issues with 5.04*** + +- It seems auto detection for the Orange Pi 2 doesn't work properly. Please have a look [in the forum](http://forum.armbian.com/index.php/topic/617-wip-orange-pi-one-support-for-the-upcoming-orange-pi-one/?p=5718). Will be fixed in 5.05 if we ever get feedback (otherwise image for Orange Pi 2 will be withdrawn +- Mali acceleration currently only working for root user. Please apply [a fix](http://forum.armbian.com/index.php/topic/617-wip-orange-pi-one-support-for-the-upcoming-orange-pi-one/?p=5719) manually or wait for 5.05 to fix this + ***Important to know*** - 1st boot takes longer (up to 5 minutes). Please do not interrupt while the red LED is blinking, the board reboots automatically one time and the green LED starts to blink when ready From 92983db9a2ed5116c103cd7dceabe3a703b26bef Mon Sep 17 00:00:00 2001 From: Igor Pecovnik Date: Mon, 29 Feb 2016 15:30:31 +0100 Subject: [PATCH 09/15] Fixed Banana PRO wireless driver in legacy kernel, module name AP6211, enabled I2S in Banana PRO legacy --- config/bananapipro.fex | 2 +- config/linux-sun7i-default.config | 5 + configuration.sh | 2 +- ...ch => 0030-ap6210_module-cubietruck.patch} | 0 .../0031-ap6211_module-bananapro.patch | 84915 ++++++++++++++++ 5 files changed, 84922 insertions(+), 2 deletions(-) rename patch/kernel/sun7i-default/{0030-ap6210_module.patch => 0030-ap6210_module-cubietruck.patch} (100%) create mode 100644 patch/kernel/sun7i-default/0031-ap6211_module-bananapro.patch diff --git a/config/bananapipro.fex b/config/bananapipro.fex index 71639825cf..3bf50f461b 100644 --- a/config/bananapipro.fex +++ b/config/bananapipro.fex @@ -942,7 +942,7 @@ bt_gpio = port:PI21<1> bt_rst = port:PB05<1> [i2s_para] -i2s_used = 0 +i2s_used = 1 i2s_channel = 2 i2s_mclk = port:PB05<2><1> i2s_bclk = port:PB06<2><1> diff --git a/config/linux-sun7i-default.config b/config/linux-sun7i-default.config index db5495b4e3..1a4642384f 100644 --- a/config/linux-sun7i-default.config +++ b/config/linux-sun7i-default.config @@ -1511,6 +1511,11 @@ CONFIG_AP6210_FW_PATH="/lib/firmware/ap6210/fw_bcmxxxx.bin" CONFIG_AP6210_NVRAM_PATH="/lib/firmware/ap6210/nvram_apxxxx.txt" CONFIG_AP6210_OOB=y # CONFIG_AP6210_SDIO_IRQ is not set +CONFIG_AP6211=m +CONFIG_AP6211_FW_PATH="/lib/firmware/ap6210/fw_bcmxxxx.bin" +CONFIG_AP6211_NVRAM_PATH="/lib/firmware/ap6210/nvram_ap6210.txt" +CONFIG_AP6211_OOB=y +# CONFIG_AP6211_SDIO_IRQ is not set CONFIG_BRCMUTIL=m CONFIG_BRCMFMAC=m CONFIG_BRCMFMAC_SDIO=y diff --git a/configuration.sh b/configuration.sh index 4f9ca8bd75..97380073d4 100644 --- a/configuration.sh +++ b/configuration.sh @@ -179,7 +179,7 @@ case $BOARD in #build 6 LINUXFAMILY="sun7i" BOOTCONFIG="Bananapi_defconfig" - MODULES="hci_uart gpio_sunxi rfcomm hidp sunxi-ir bonding spi_sun7i 8021q a20_tp ap6210" + MODULES="hci_uart gpio_sunxi rfcomm hidp sunxi-ir bonding spi_sun7i 8021q a20_tp ap6211" MODULES_NEXT="brcmfmac bonding" DESKTOP_TARGET="trusty,%" ;; diff --git a/patch/kernel/sun7i-default/0030-ap6210_module.patch b/patch/kernel/sun7i-default/0030-ap6210_module-cubietruck.patch similarity index 100% rename from patch/kernel/sun7i-default/0030-ap6210_module.patch rename to patch/kernel/sun7i-default/0030-ap6210_module-cubietruck.patch diff --git a/patch/kernel/sun7i-default/0031-ap6211_module-bananapro.patch b/patch/kernel/sun7i-default/0031-ap6211_module-bananapro.patch new file mode 100644 index 0000000000..7dd09ba3dd --- /dev/null +++ b/patch/kernel/sun7i-default/0031-ap6211_module-bananapro.patch @@ -0,0 +1,84915 @@ +diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig +old mode 100644 +new mode 100755 +index a17fd93..6afeab3 +--- a/drivers/net/wireless/Kconfig ++++ b/drivers/net/wireless/Kconfig +@@ -278,7 +278,8 @@ source "drivers/net/wireless/ath/Kconfig" + source "drivers/net/wireless/b43/Kconfig" + source "drivers/net/wireless/b43legacy/Kconfig" + source "drivers/net/wireless/bcmdhd/Kconfig" + source "drivers/net/wireless/ap6210/Kconfig" ++source "drivers/net/wireless/ap6211/Kconfig" + source "drivers/net/wireless/brcm80211/Kconfig" + source "drivers/net/wireless/bcm4330/Kconfig" + source "drivers/net/wireless/hostap/Kconfig" +diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile +old mode 100644 +new mode 100755 +index 0db00ba..a970c43 +--- a/drivers/net/wireless/Makefile ++++ b/drivers/net/wireless/Makefile +@@ -65,7 +65,8 @@ obj-$(CONFIG_IWM) += iwmc3200wifi/ + obj-$(CONFIG_MWIFIEX) += mwifiex/ + + obj-$(CONFIG_BCMDHD) += bcmdhd/ + obj-$(CONFIG_AP6210) += ap6210/ ++obj-$(CONFIG_AP6211) += ap6211/ + + obj-$(CONFIG_BRCMFMAC) += brcm80211/ + obj-$(CONFIG_BRCMSMAC) += brcm80211/ +diff --git a/drivers/net/wireless/ap6211/Kconfig b/drivers/net/wireless/ap6211/Kconfig +new file mode 100755 +index 0000000..9756ac7 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/Kconfig +@@ -0,0 +1,45 @@ ++config AP6211 ++ tristate "AMPAK AP6211 wireless/bluetooth module support" ++ depends on MMC ++ default n ++ ---help--- ++ This module adds support for the wireless and bluetooth ++ module of the CubieTruck. ++ ++config AP6211_FW_PATH ++ depends on AP6211 ++ string "Firmware path" ++ default "/system/vendor/modules/fw_bcmxxxx.bin" ++ ---help--- ++ Path to the firmware file. ++ ++config AP6211_NVRAM_PATH ++ depends on AP6211 ++ string "NVRAM path" ++ default "/system/vendor/modules/nvram_apxxxx.txt" ++ ---help--- ++ Path to the calibration file. ++ ++config AP6211_WEXT ++ bool "Enable WEXT support" ++ depends on AP6211 && CFG80211 = n ++ select WIRELESS_EXT ++ select WEXT_PRIV ++ help ++ Enables WEXT support ++ ++choice ++ depends on AP6211 ++ prompt "Interrupt type" ++config AP6211_OOB ++ depends on AP6211 ++ bool "Out-of-Band Interrupt" ++ ---help--- ++ Interrupt through WL_HOST_WAKE. ++config AP6211_SDIO_IRQ ++ depends on AP6211 ++ bool "In-Band Interrupt" ++ default y ++ ---help--- ++ Interrupt through SDIO DAT[1] ++endchoice +diff --git a/drivers/net/wireless/ap6211/Makefile b/drivers/net/wireless/ap6211/Makefile +new file mode 100755 +index 0000000..59ef7c8 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/Makefile +@@ -0,0 +1,65 @@ ++# ap6211 ++DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \ ++ -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ ++ -DDHDTHREAD -DDHD_DEBUG -DSDTEST -DBDC -DTOE \ ++ -DDHD_BCMEVENTS -DSHOW_EVENTS -DPROP_TXSTATUS -DBCMDBG \ ++ -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DBCMPLATFORM_BUS -DWLP2P \ ++ -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ ++ -DKEEP_ALIVE -DPKT_FILTER_SUPPORT \ ++ -DEMBEDDED_PLATFORM -DENABLE_INSMOD_NO_FW_LOAD -DPNO_SUPPORT \ ++ -DDHD_USE_IDLECOUNT -DSET_RANDOM_MAC_SOFTAP -DVSDB \ ++ -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -DSDIO_CRC_ERROR_FIX \ ++ -DESCAN_RESULT_PATCH -DHT40_GO -DPASS_ARP_PACKET -DSUPPORT_PM2_ONLY \ ++ -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT -DAMPDU_HOSTREORDER \ ++ -DDISABLE_FW_ROAM_SUSPEND -DDISABLE_BUILTIN_ROAM \ ++ -DCUSTOM_SDIO_F2_BLKSIZE=128 -DWL_SDO -DWL_SUPPORT_BACKPORTED_KPATCHES\ ++ -Idrivers/net/wireless/ap6211 -Idrivers/net/wireless/ap6211/include ++ ++DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o \ ++ dhd_linux_sched.o dhd_sdio.o bcmwifi_channels.o bcmevent.o hndpmu.o \ ++ bcmsdh.o dhd_cdc.o bcmsdh_linux.o dhd_common.o linux_osl.o \ ++ bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o wldev_common.o wl_android.o \ ++ ap6211_gpio_wifi.o ap6211_gpio_bt.o ++ ++obj-$(CONFIG_AP6211) += ap6211.o ++ap6211-objs += $(DHDOFILES) ++ ++DHDOFILES += dhd_gpio.o ++DHDCFLAGS += -DCUSTOMER_HW ++#DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI ++ ++ifeq ($(CONFIG_AP6211_OOB),y) ++DHDCFLAGS += -DOOB_INTR_ONLY -DHW_OOB -DCUSTOMER_OOB ++else ++DHDCFLAGS += -DSDIO_ISR_THREAD ++endif ++ ++ifeq ($(CONFIG_AP6211_AG),y) ++ DHDCFLAGS += -DBAND_AG ++endif ++ ++ifneq ($(CONFIG_WIRELESS_EXT),) ++ap6211-objs += wl_iw.o ++DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT -DUSE_IW ++endif ++ifneq ($(CONFIG_CFG80211),) ++ap6211-objs += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o dhd_cfg80211.o ++DHDCFLAGS += -DWL_CFG80211 -DWL_CFG80211_STA_EVENT ++DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-65 ++DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=15 ++DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=28000 ++DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=7 ++#DHDCFLAGS += -fno-aggressive-loop-optimizations ++endif ++ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) ++DHDCFLAGS += -DWL_SCHED_SCAN ++endif ++EXTRA_CFLAGS = $(DHDCFLAGS) ++ifeq ($(CONFIG_AP6211),m) ++EXTRA_LDFLAGS += --strip-debug ++endif ++ ++# GPIO Power Management Modules ++ ++#obj-$(CONFIG_AP6211) += ap6211_gpio_wifi.o ++#obj-$(CONFIG_AP6211) += ap6211_gpio_bt.o +diff --git a/drivers/net/wireless/ap6211/aiutils.c b/drivers/net/wireless/ap6211/aiutils.c +new file mode 100755 +index 0000000..bc116d7 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/aiutils.c +@@ -0,0 +1,873 @@ ++/* ++ * Misc utility routines for accessing chip-specific features ++ * of the SiliconBackplane-based Broadcom chips. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: aiutils.c 347614 2012-07-27 10:24:51Z $ ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "siutils_priv.h" ++ ++#include ++ ++#define BCM47162_DMP() (0) ++#define BCM5357_DMP() (0) ++#define remap_coreid(sih, coreid) (coreid) ++#define remap_corerev(sih, corerev) (corerev) ++ ++/* EROM parsing */ ++ ++static uint32 ++get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match) ++{ ++ uint32 ent; ++ uint inv = 0, nom = 0; ++ ++ while (TRUE) { ++ ent = R_REG(si_osh(sih), *eromptr); ++ (*eromptr)++; ++ ++ if (mask == 0) ++ break; ++ ++ if ((ent & ER_VALID) == 0) { ++ inv++; ++ continue; ++ } ++ ++ if (ent == (ER_END | ER_VALID)) ++ break; ++ ++ if ((ent & mask) == match) ++ break; ++ ++ nom++; ++ } ++ ++ AP6211_DEBUG("%s: Returning ent 0x%08x\n", __FUNCTION__, ent); ++ if (inv + nom) { ++ AP6211_DEBUG(" after %d invalid and %d non-matching entries\n", inv, nom); ++ } ++ return ent; ++} ++ ++static uint32 ++get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh, ++ uint32 *sizel, uint32 *sizeh) ++{ ++ uint32 asd, sz, szd; ++ ++ asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID); ++ if (((asd & ER_TAG1) != ER_ADD) || ++ (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) || ++ ((asd & AD_ST_MASK) != st)) { ++ /* This is not what we want, "push" it back */ ++ (*eromptr)--; ++ return 0; ++ } ++ *addrl = asd & AD_ADDR_MASK; ++ if (asd & AD_AG32) ++ *addrh = get_erom_ent(sih, eromptr, 0, 0); ++ else ++ *addrh = 0; ++ *sizeh = 0; ++ sz = asd & AD_SZ_MASK; ++ if (sz == AD_SZ_SZD) { ++ szd = get_erom_ent(sih, eromptr, 0, 0); ++ *sizel = szd & SD_SZ_MASK; ++ if (szd & SD_SG32) ++ *sizeh = get_erom_ent(sih, eromptr, 0, 0); ++ } else ++ *sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT); ++ ++ AP6211_DEBUG(" SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n", ++ sp, ad, st, *sizeh, *sizel, *addrh, *addrl); ++ ++ return asd; ++} ++ ++static void ++ai_hwfixup(si_info_t *sii) ++{ ++} ++ ++ ++/* parse the enumeration rom to identify all cores */ ++void ++ai_scan(si_t *sih, void *regs, uint devid) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ chipcregs_t *cc = (chipcregs_t *)regs; ++ uint32 erombase, *eromptr, *eromlim; ++ ++ erombase = R_REG(sii->osh, &cc->eromptr); ++ ++ switch (BUSTYPE(sih->bustype)) { ++ case SI_BUS: ++ eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); ++ break; ++ ++ case PCI_BUS: ++ /* Set wrappers address */ ++ sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE); ++ ++ /* Now point the window at the erom */ ++ OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase); ++ eromptr = regs; ++ break; ++ ++ case SPI_BUS: ++ case SDIO_BUS: ++ eromptr = (uint32 *)(uintptr)erombase; ++ break; ++ ++ case PCMCIA_BUS: ++ default: ++ AP6211_ERR("Don't know how to do AXI enumertion on bus %d\n", sih->bustype); ++ ASSERT(0); ++ return; ++ } ++ eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); ++ ++ AP6211_DEBUG("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n", ++ regs, erombase, eromptr, eromlim); ++ while (eromptr < eromlim) { ++ uint32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; ++ uint32 mpd, asd, addrl, addrh, sizel, sizeh; ++ uint i, j, idx; ++ bool br; ++ ++ br = FALSE; ++ ++ /* Grok a component */ ++ cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI); ++ if (cia == (ER_END | ER_VALID)) { ++ AP6211_DEBUG("Found END of erom after %d cores\n", sii->numcores); ++ ai_hwfixup(sii); ++ return; ++ } ++ ++ cib = get_erom_ent(sih, &eromptr, 0, 0); ++ ++ if ((cib & ER_TAG) != ER_CI) { ++ AP6211_ERR("CIA not followed by CIB\n"); ++ goto error; ++ } ++ ++ cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT; ++ mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT; ++ crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT; ++ nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT; ++ nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT; ++ nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; ++ nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; ++ ++#ifdef BCMDBG_SI ++ AP6211_DEBUG("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, " ++ "nsw = %d, nmp = %d & nsp = %d\n", ++ mfg, cid, crev, eromptr - 1, nmw, nsw, nmp, nsp); ++#else ++ BCM_REFERENCE(crev); ++#endif ++ ++ if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0)) ++ continue; ++ if ((nmw + nsw == 0)) { ++ /* A component which is not a core */ ++ if (cid == OOB_ROUTER_CORE_ID) { ++ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, ++ &addrl, &addrh, &sizel, &sizeh); ++ if (asd != 0) { ++ sii->oob_router = addrl; ++ } ++ } ++ if (cid != GMAC_COMMON_4706_CORE_ID) ++ continue; ++ } ++ ++ idx = sii->numcores; ++ ++ sii->cia[idx] = cia; ++ sii->cib[idx] = cib; ++ sii->coreid[idx] = remap_coreid(sih, cid); ++ ++ for (i = 0; i < nmp; i++) { ++ mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); ++ if ((mpd & ER_TAG) != ER_MP) { ++ AP6211_ERR("Not enough MP entries for component 0x%x\n", cid); ++ goto error; ++ } ++ AP6211_DEBUG(" Master port %d, mp: %d id: %d\n", i, ++ (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT, ++ (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT); ++ } ++ ++ /* First Slave Address Descriptor should be port 0: ++ * the main register space for the core ++ */ ++ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); ++ if (asd == 0) { ++ do { ++ /* Try again to see if it is a bridge */ ++ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, ++ &sizel, &sizeh); ++ if (asd != 0) ++ br = TRUE; ++ else { ++ if (br == TRUE) { ++ break; ++ } ++ else if ((addrh != 0) || (sizeh != 0) || ++ (sizel != SI_CORE_SIZE)) { ++ AP6211_ERR("addrh = 0x%x\t sizeh = 0x%x\t size1 =" ++ "0x%x\n", addrh, sizeh, sizel); ++ AP6211_ERR("First Slave ASD for" ++ "core 0x%04x malformed " ++ "(0x%08x)\n", cid, asd); ++ goto error; ++ } ++ } ++ } while (1); ++ } ++ sii->coresba[idx] = addrl; ++ sii->coresba_size[idx] = sizel; ++ /* Get any more ASDs in port 0 */ ++ j = 1; ++ do { ++ asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, ++ &sizel, &sizeh); ++ if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) { ++ sii->coresba2[idx] = addrl; ++ sii->coresba2_size[idx] = sizel; ++ } ++ j++; ++ } while (asd != 0); ++ ++ /* Go through the ASDs for other slave ports */ ++ for (i = 1; i < nsp; i++) { ++ j = 0; ++ do { ++ asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh, ++ &sizel, &sizeh); ++ ++ if (asd == 0) ++ break; ++ j++; ++ } while (1); ++ if (j == 0) { ++ AP6211_ERR(" SP %d has no address descriptors\n", i); ++ goto error; ++ } ++ } ++ ++ /* Now get master wrappers */ ++ for (i = 0; i < nmw; i++) { ++ asd = get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, &addrh, ++ &sizel, &sizeh); ++ if (asd == 0) { ++ AP6211_ERR("Missing descriptor for MW %d\n", i); ++ goto error; ++ } ++ if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { ++ AP6211_ERR("Master wrapper %d is not 4KB\n", i); ++ goto error; ++ } ++ if (i == 0) ++ sii->wrapba[idx] = addrl; ++ } ++ ++ /* And finally slave wrappers */ ++ for (i = 0; i < nsw; i++) { ++ uint fwp = (nsp == 1) ? 0 : 1; ++ asd = get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, &addrl, &addrh, ++ &sizel, &sizeh); ++ if (asd == 0) { ++ AP6211_ERR("Missing descriptor for SW %d\n", i); ++ goto error; ++ } ++ if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { ++ AP6211_ERR("Slave wrapper %d is not 4KB\n", i); ++ goto error; ++ } ++ if ((nmw == 0) && (i == 0)) ++ sii->wrapba[idx] = addrl; ++ } ++ ++ ++ /* Don't record bridges */ ++ if (br) ++ continue; ++ ++ /* Done with core */ ++ sii->numcores++; ++ } ++ ++ AP6211_ERR("Reached end of erom without finding END"); ++ ++error: ++ sii->numcores = 0; ++ return; ++} ++ ++/* This function changes the logical "focus" to the indicated core. ++ * Return the current core's virtual address. ++ */ ++void * ++ai_setcoreidx(si_t *sih, uint coreidx) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint32 addr, wrap; ++ void *regs; ++ ++ if (coreidx >= MIN(sii->numcores, SI_MAXCORES)) ++ return (NULL); ++ ++ addr = sii->coresba[coreidx]; ++ wrap = sii->wrapba[coreidx]; ++ ++ /* ++ * If the user has provided an interrupt mask enabled function, ++ * then assert interrupts are disabled before switching the core. ++ */ ++ ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); ++ ++ switch (BUSTYPE(sih->bustype)) { ++ case SI_BUS: ++ /* map new one */ ++ if (!sii->regs[coreidx]) { ++ sii->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE); ++ ASSERT(GOODREGS(sii->regs[coreidx])); ++ } ++ sii->curmap = regs = sii->regs[coreidx]; ++ if (!sii->wrappers[coreidx]) { ++ sii->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE); ++ ASSERT(GOODREGS(sii->wrappers[coreidx])); ++ } ++ sii->curwrap = sii->wrappers[coreidx]; ++ break; ++ ++ ++ case SPI_BUS: ++ case SDIO_BUS: ++ sii->curmap = regs = (void *)((uintptr)addr); ++ sii->curwrap = (void *)((uintptr)wrap); ++ break; ++ ++ case PCMCIA_BUS: ++ default: ++ ASSERT(0); ++ regs = NULL; ++ break; ++ } ++ ++ sii->curmap = regs; ++ sii->curidx = coreidx; ++ ++ return regs; ++} ++ ++void ++ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ chipcregs_t *cc = NULL; ++ uint32 erombase, *eromptr, *eromlim; ++ uint i, j, cidx; ++ uint32 cia, cib, nmp, nsp; ++ uint32 asd, addrl, addrh, sizel, sizeh; ++ ++ for (i = 0; i < sii->numcores; i++) { ++ if (sii->coreid[i] == CC_CORE_ID) { ++ cc = (chipcregs_t *)sii->regs[i]; ++ break; ++ } ++ } ++ if (cc == NULL) ++ goto error; ++ ++ erombase = R_REG(sii->osh, &cc->eromptr); ++ eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); ++ eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); ++ ++ cidx = sii->curidx; ++ cia = sii->cia[cidx]; ++ cib = sii->cib[cidx]; ++ ++ nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; ++ nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; ++ ++ /* scan for cores */ ++ while (eromptr < eromlim) { ++ if ((get_erom_ent(sih, &eromptr, ER_TAG, ER_CI) == cia) && ++ (get_erom_ent(sih, &eromptr, 0, 0) == cib)) { ++ break; ++ } ++ } ++ ++ /* skip master ports */ ++ for (i = 0; i < nmp; i++) ++ get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); ++ ++ /* Skip ASDs in port 0 */ ++ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); ++ if (asd == 0) { ++ /* Try again to see if it is a bridge */ ++ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, ++ &sizel, &sizeh); ++ } ++ ++ j = 1; ++ do { ++ asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, ++ &sizel, &sizeh); ++ j++; ++ } while (asd != 0); ++ ++ /* Go through the ASDs for other slave ports */ ++ for (i = 1; i < nsp; i++) { ++ j = 0; ++ do { ++ asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh, ++ &sizel, &sizeh); ++ if (asd == 0) ++ break; ++ ++ if (!asidx--) { ++ *addr = addrl; ++ *size = sizel; ++ return; ++ } ++ j++; ++ } while (1); ++ ++ if (j == 0) { ++ AP6211_ERR(" SP %d has no address descriptors\n", i); ++ break; ++ } ++ } ++ ++error: ++ *size = 0; ++ return; ++} ++ ++/* Return the number of address spaces in current core */ ++int ++ai_numaddrspaces(si_t *sih) ++{ ++ return 2; ++} ++ ++/* Return the address of the nth address space in the current core */ ++uint32 ++ai_addrspace(si_t *sih, uint asidx) ++{ ++ si_info_t *sii; ++ uint cidx; ++ ++ sii = SI_INFO(sih); ++ cidx = sii->curidx; ++ ++ if (asidx == 0) ++ return sii->coresba[cidx]; ++ else if (asidx == 1) ++ return sii->coresba2[cidx]; ++ else { ++ AP6211_ERR("%s: Need to parse the erom again to find addr space %d\n", ++ __FUNCTION__, asidx); ++ return 0; ++ } ++} ++ ++/* Return the size of the nth address space in the current core */ ++uint32 ++ai_addrspacesize(si_t *sih, uint asidx) ++{ ++ si_info_t *sii; ++ uint cidx; ++ ++ sii = SI_INFO(sih); ++ cidx = sii->curidx; ++ ++ if (asidx == 0) ++ return sii->coresba_size[cidx]; ++ else if (asidx == 1) ++ return sii->coresba2_size[cidx]; ++ else { ++ AP6211_ERR("%s: Need to parse the erom again to find addr space %d\n", ++ __FUNCTION__, asidx); ++ return 0; ++ } ++} ++ ++uint ++ai_flag(si_t *sih) ++{ ++ si_info_t *sii; ++ aidmp_t *ai; ++ ++ sii = SI_INFO(sih); ++ if (BCM47162_DMP()) { ++ AP6211_ERR("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__); ++ return sii->curidx; ++ } ++ if (BCM5357_DMP()) { ++ AP6211_ERR("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__); ++ return sii->curidx; ++ } ++ ai = sii->curwrap; ++ ++ return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f); ++} ++ ++void ++ai_setint(si_t *sih, int siflag) ++{ ++} ++ ++uint ++ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint32 *map = (uint32 *) sii->curwrap; ++ ++ if (mask || val) { ++ uint32 w = R_REG(sii->osh, map+(offset/4)); ++ w &= ~mask; ++ w |= val; ++ W_REG(sii->osh, map+(offset/4), val); ++ } ++ ++ return (R_REG(sii->osh, map+(offset/4))); ++} ++ ++uint ++ai_corevendor(si_t *sih) ++{ ++ si_info_t *sii; ++ uint32 cia; ++ ++ sii = SI_INFO(sih); ++ cia = sii->cia[sii->curidx]; ++ return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT); ++} ++ ++uint ++ai_corerev(si_t *sih) ++{ ++ si_info_t *sii; ++ uint32 cib; ++ ++ sii = SI_INFO(sih); ++ cib = sii->cib[sii->curidx]; ++ return remap_corerev(sih, (cib & CIB_REV_MASK) >> CIB_REV_SHIFT); ++} ++ ++bool ++ai_iscoreup(si_t *sih) ++{ ++ si_info_t *sii; ++ aidmp_t *ai; ++ ++ sii = SI_INFO(sih); ++ ai = sii->curwrap; ++ ++ return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) && ++ ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0)); ++} ++ ++/* ++ * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation, ++ * switch back to the original core, and return the new value. ++ * ++ * When using the silicon backplane, no fiddling with interrupts or core switches is needed. ++ * ++ * Also, when using pci/pcie, we can optimize away the core switching for pci registers ++ * and (on newer pci cores) chipcommon registers. ++ */ ++uint ++ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) ++{ ++ uint origidx = 0; ++ uint32 *r = NULL; ++ uint w; ++ uint intr_val = 0; ++ bool fast = FALSE; ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ ASSERT(GOODIDX(coreidx)); ++ ASSERT(regoff < SI_CORE_SIZE); ++ ASSERT((val & ~mask) == 0); ++ ++ if (coreidx >= SI_MAXCORES) ++ return 0; ++ ++ if (BUSTYPE(sih->bustype) == SI_BUS) { ++ /* If internal bus, we can always get at everything */ ++ fast = TRUE; ++ /* map if does not exist */ ++ if (!sii->regs[coreidx]) { ++ sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx], ++ SI_CORE_SIZE); ++ ASSERT(GOODREGS(sii->regs[coreidx])); ++ } ++ r = (uint32 *)((uchar *)sii->regs[coreidx] + regoff); ++ } else if (BUSTYPE(sih->bustype) == PCI_BUS) { ++ /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ ++ ++ if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { ++ /* Chipc registers are mapped at 12KB */ ++ ++ fast = TRUE; ++ r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff); ++ } else if (sii->pub.buscoreidx == coreidx) { ++ /* pci registers are at either in the last 2KB of an 8KB window ++ * or, in pcie and pci rev 13 at 8KB ++ */ ++ fast = TRUE; ++ if (SI_FAST(sii)) ++ r = (uint32 *)((char *)sii->curmap + ++ PCI_16KB0_PCIREGS_OFFSET + regoff); ++ else ++ r = (uint32 *)((char *)sii->curmap + ++ ((regoff >= SBCONFIGOFF) ? ++ PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + ++ regoff); ++ } ++ } ++ ++ if (!fast) { ++ INTR_OFF(sii, intr_val); ++ ++ /* save current core index */ ++ origidx = si_coreidx(&sii->pub); ++ ++ /* switch core */ ++ r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff); ++ } ++ ASSERT(r != NULL); ++ ++ /* mask and set */ ++ if (mask || val) { ++ w = (R_REG(sii->osh, r) & ~mask) | val; ++ W_REG(sii->osh, r, w); ++ } ++ ++ /* readback */ ++ w = R_REG(sii->osh, r); ++ ++ if (!fast) { ++ /* restore core index */ ++ if (origidx != coreidx) ++ ai_setcoreidx(&sii->pub, origidx); ++ ++ INTR_RESTORE(sii, intr_val); ++ } ++ ++ return (w); ++} ++ ++void ++ai_core_disable(si_t *sih, uint32 bits) ++{ ++ si_info_t *sii; ++ volatile uint32 dummy; ++ uint32 status; ++ aidmp_t *ai; ++ ++ sii = SI_INFO(sih); ++ ++ ASSERT(GOODREGS(sii->curwrap)); ++ ai = sii->curwrap; ++ ++ /* if core is already in reset, just return */ ++ if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) ++ return; ++ ++ /* ensure there are no pending backplane operations */ ++ SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); ++ ++ /* if pending backplane ops still, try waiting longer */ ++ if (status != 0) { ++ /* 300usecs was sufficient to allow backplane ops to clear for big hammer */ ++ /* during driver load we may need more time */ ++ SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 10000); ++ /* if still pending ops, continue on and try disable anyway */ ++ /* this is in big hammer path, so don't call wl_reinit in this case... */ ++ } ++ ++ W_REG(sii->osh, &ai->ioctrl, bits); ++ dummy = R_REG(sii->osh, &ai->ioctrl); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(10); ++ ++ W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); ++ dummy = R_REG(sii->osh, &ai->resetctrl); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++} ++ ++/* reset and re-enable a core ++ * inputs: ++ * bits - core specific bits that are set during and after reset sequence ++ * resetbits - core specific bits that are set only during reset sequence ++ */ ++void ++ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits) ++{ ++ si_info_t *sii; ++ aidmp_t *ai; ++ volatile uint32 dummy; ++ ++ sii = SI_INFO(sih); ++ ASSERT(GOODREGS(sii->curwrap)); ++ ai = sii->curwrap; ++ ++ /* ++ * Must do the disable sequence first to work for arbitrary current core state. ++ */ ++ ai_core_disable(sih, (bits | resetbits)); ++ ++ /* ++ * Now do the initialization sequence. ++ */ ++ W_REG(sii->osh, &ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN)); ++ dummy = R_REG(sii->osh, &ai->ioctrl); ++ BCM_REFERENCE(dummy); ++ ++ W_REG(sii->osh, &ai->resetctrl, 0); ++ dummy = R_REG(sii->osh, &ai->resetctrl); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++ ++ W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN)); ++ dummy = R_REG(sii->osh, &ai->ioctrl); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++} ++ ++void ++ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii; ++ aidmp_t *ai; ++ uint32 w; ++ ++ sii = SI_INFO(sih); ++ ++ if (BCM47162_DMP()) { ++ AP6211_ERR("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", ++ __FUNCTION__); ++ return; ++ } ++ if (BCM5357_DMP()) { ++ AP6211_ERR("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", ++ __FUNCTION__); ++ return; ++ } ++ ++ ASSERT(GOODREGS(sii->curwrap)); ++ ai = sii->curwrap; ++ ++ ASSERT((val & ~mask) == 0); ++ ++ if (mask || val) { ++ w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); ++ W_REG(sii->osh, &ai->ioctrl, w); ++ } ++} ++ ++uint32 ++ai_core_cflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii; ++ aidmp_t *ai; ++ uint32 w; ++ ++ sii = SI_INFO(sih); ++ if (BCM47162_DMP()) { ++ AP6211_ERR("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", ++ __FUNCTION__); ++ return 0; ++ } ++ if (BCM5357_DMP()) { ++ AP6211_ERR("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", ++ __FUNCTION__); ++ return 0; ++ } ++ ++ ASSERT(GOODREGS(sii->curwrap)); ++ ai = sii->curwrap; ++ ++ ASSERT((val & ~mask) == 0); ++ ++ if (mask || val) { ++ w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); ++ W_REG(sii->osh, &ai->ioctrl, w); ++ } ++ ++ return R_REG(sii->osh, &ai->ioctrl); ++} ++ ++uint32 ++ai_core_sflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii; ++ aidmp_t *ai; ++ uint32 w; ++ ++ sii = SI_INFO(sih); ++ if (BCM47162_DMP()) { ++ AP6211_ERR("%s: Accessing MIPS DMP register (iostatus) on 47162a0", ++ __FUNCTION__); ++ return 0; ++ } ++ if (BCM5357_DMP()) { ++ AP6211_ERR("%s: Accessing USB20H DMP register (iostatus) on 5357\n", ++ __FUNCTION__); ++ return 0; ++ } ++ ++ ASSERT(GOODREGS(sii->curwrap)); ++ ai = sii->curwrap; ++ ++ ASSERT((val & ~mask) == 0); ++ ASSERT((mask & ~SISF_CORE_BITS) == 0); ++ ++ if (mask || val) { ++ w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val); ++ W_REG(sii->osh, &ai->iostatus, w); ++ } ++ ++ return R_REG(sii->osh, &ai->iostatus); ++} +diff --git a/drivers/net/wireless/ap6211/ap6211.h b/drivers/net/wireless/ap6211/ap6211.h +new file mode 100755 +index 0000000..90e7d8d +--- /dev/null ++++ b/drivers/net/wireless/ap6211/ap6211.h +@@ -0,0 +1,22 @@ ++#ifndef __AP6211_H__ ++#define __AP6211_H__ ++ ++#define AP6211_EMERG(...) pr_emerg("[ap6211] "__VA_ARGS__) ++#define AP6211_ALERT(...) pr_alert("[ap6211] "__VA_ARGS__) ++#define AP6211_CRIT(...) pr_crit("[ap6211] "__VA_ARGS__) ++#define AP6211_ERR(...) pr_err("[ap6211] "__VA_ARGS__) ++#define AP6211_WARN(...) pr_warn("[ap6211] "__VA_ARGS__) ++#define AP6211_NOTICE(...) pr_notice("[ap6211] "__VA_ARGS__) ++#define AP6211_INFO(...) pr_info("[ap6211] "__VA_ARGS__) ++#define AP6211_DEBUG(...) pr_debug("[ap6211] "__VA_ARGS__) ++#define AP6211_DUMP(...) pr_debug(__VA_ARGS__) ++#define AP6211_CONT(...) pr_cont(__VA_ARGS__) ++ ++extern int __init sw_rfkill_init(void); ++extern void __exit sw_rfkill_exit(void); ++ ++extern int __init ap6211_gpio_wifi_init(void); ++extern void __exit ap6211_gpio_wifi_exit(void); ++ ++ ++#endif /* __AP6211_H__ */ +diff --git a/drivers/net/wireless/ap6211/ap6211_gpio.h b/drivers/net/wireless/ap6211/ap6211_gpio.h +new file mode 100755 +index 0000000..96a3166 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/ap6211_gpio.h +@@ -0,0 +1,9 @@ ++#ifndef __AP6211_GPIO_H__ ++#define __AP6211_GPIO_H__ ++ ++extern int ap6211_gpio_wifi_get_mod_type(void); ++extern int ap6211_gpio_wifi_gpio_ctrl(char* name, int level); ++extern void ap6211_gpio_wifi_power(int on); ++extern char *ap6211_gpio_wifi_get_name(int module_sel); ++ ++#endif /* __AP6211_GPIO_H__ */ +diff --git a/drivers/net/wireless/ap6211/ap6211_gpio_bt.c b/drivers/net/wireless/ap6211/ap6211_gpio_bt.c +new file mode 100755 +index 0000000..4686615 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/ap6211_gpio_bt.c +@@ -0,0 +1,164 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if (defined CONFIG_MMC) ++#include "ap6211_gpio.h" ++#else ++static __inline int ap6211_gpio_wifi_get_mod_type(void) ++{ ++ AP6211_DEBUG("%s : not implemented!\n", __FUNCTION__ ); ++ return 0; ++} ++static __inline int ap6211_gpio_wifi_gpio_ctrl(char* name, int level) ++{ ++ AP6211_DEBUG("%s : not implemented!\n", __FUNCTION__ ); ++ return -1; ++} ++#endif ++ ++#include ++ ++static const char bt_name[] = "bcm40183"; ++static struct rfkill *sw_rfkill; ++static int bt_used; ++ ++static int rfkill_set_power(void *data, bool blocked) ++{ ++ unsigned int mod_sel = ap6211_gpio_wifi_get_mod_type(); ++ ++ AP6211_DEBUG("rfkill set power %s\n", ( blocked ? "blocked" : "unblocked" )); ++ ++ switch (mod_sel) ++ { ++ case 2: /* bcm40183 */ ++ if (!blocked) { ++ ap6211_gpio_wifi_gpio_ctrl("bcm40183_bt_regon", 1); ++ ap6211_gpio_wifi_gpio_ctrl("bcm40183_bt_rst", 1); ++ } else { ++ ap6211_gpio_wifi_gpio_ctrl("bcm40183_bt_rst", 0); ++ ap6211_gpio_wifi_gpio_ctrl("bcm40183_bt_regon", 0); ++ } ++ AP6211_ERR("Using %s configuration.\n", ap6211_gpio_wifi_get_name(mod_sel) ); ++ break; ++ case 3: /* realtek rtl8723as */ ++ if (!blocked) { ++ ap6211_gpio_wifi_gpio_ctrl("rtk_rtl8723as_bt_dis", 1); ++ } else { ++ ap6211_gpio_wifi_gpio_ctrl("rtk_rtl8723as_bt_dis", 0); ++ } ++ AP6211_ERR("Using %s configuration.\n", ap6211_gpio_wifi_get_name(mod_sel) ); ++ break; ++ case 7: /* ap6211 */ ++ case 8: /* ap6330 */ ++ if (!blocked) { ++ ap6211_gpio_wifi_gpio_ctrl("ap6xxx_bt_regon", 1); ++ } else { ++ ap6211_gpio_wifi_gpio_ctrl("ap6xxx_bt_regon", 0); ++ } ++ AP6211_ERR("Using %s configuration.\n", ap6211_gpio_wifi_get_name(mod_sel) ); ++ break; ++ case 10: /* realtek rtl8723au */ ++ if (!blocked) { ++ ap6211_gpio_wifi_gpio_ctrl("rtl8723au_bt", 1); ++ } else { ++ ap6211_gpio_wifi_gpio_ctrl("rtl8723au_bt", 0); ++ } ++ AP6211_ERR("Using %s configuration.\n", ap6211_gpio_wifi_get_name(mod_sel) ); ++ break; ++ default: ++ AP6211_ERR("no bluetooth module matched.\n" ); ++ } ++ ++ msleep(10); ++ return 0; ++} ++ ++static struct rfkill_ops sw_rfkill_ops = { ++ .set_block = rfkill_set_power, ++}; ++ ++static int sw_rfkill_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ sw_rfkill = rfkill_alloc(bt_name, &pdev->dev, ++ RFKILL_TYPE_BLUETOOTH, &sw_rfkill_ops, NULL); ++ if (unlikely(!sw_rfkill)) { ++ AP6211_DEBUG("Unable to alocate rfkill structure.\n" ); ++ return -ENOMEM; ++ } ++ ++ ret = rfkill_register(sw_rfkill); ++ if (unlikely(ret)) { ++ AP6211_DEBUG("Unable to register rfkill structure.\n" ); ++ rfkill_destroy(sw_rfkill); ++ } ++ AP6211_DEBUG("rfkill structure registered successfully.\n" ); ++ return ret; ++} ++ ++static int sw_rfkill_remove(struct platform_device *pdev) ++{ ++ if (likely(sw_rfkill)) { ++ rfkill_unregister(sw_rfkill); ++ rfkill_destroy(sw_rfkill); ++ AP6211_DEBUG("rfkill structure removed successfully.\n" ); ++ } ++ ++ return 0; ++} ++ ++static struct platform_driver sw_rfkill_driver = { ++ .probe = sw_rfkill_probe, ++ .remove = sw_rfkill_remove, ++ .driver = { ++ .name = "sunxi-rfkill", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static struct platform_device sw_rfkill_dev = { ++ .name = "sunxi-rfkill", ++}; ++ ++int __init sw_rfkill_init(void) ++{ ++ if (SCRIPT_PARSER_OK != script_parser_fetch("bt_para", "bt_used", &bt_used, 1)) { ++ AP6211_DEBUG("parse bt_used failed in script.fex.\n" ); ++ return -1; ++ } ++ ++ if (!bt_used) { ++ AP6211_ERR("bluetooth is disable in script.fex.\n" ); ++ return 0; ++ } ++ ++ platform_device_register(&sw_rfkill_dev); ++ AP6211_ERR("platform device registered successfully.\n" ); ++ return platform_driver_register(&sw_rfkill_driver); ++} ++ ++void __exit sw_rfkill_exit(void) ++{ ++ if (!bt_used) { ++ AP6211_ERR("exit no bt used in configuration\n" ); ++ return ; ++ } ++ ++ platform_device_unregister(&sw_rfkill_dev); ++ platform_driver_unregister(&sw_rfkill_driver); ++} ++ ++/* ++module_init(sw_rfkill_init); ++module_exit(sw_rfkill_exit); ++ ++MODULE_DESCRIPTION("sunxi-rfkill driver"); ++MODULE_AUTHOR("Aaron.magic"); ++MODULE_LICENSE("GPL"); ++*/ ++ +diff --git a/drivers/net/wireless/ap6211/ap6211_gpio_wifi.c b/drivers/net/wireless/ap6211/ap6211_gpio_wifi.c +new file mode 100755 +index 0000000..916749d +--- /dev/null ++++ b/drivers/net/wireless/ap6211/ap6211_gpio_wifi.c +@@ -0,0 +1,463 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static char *wifi_para = "sdio_wifi_pro_para"; /*modify by lemaker team for ap6211*/ ++ ++struct ap6211_gpio_wifi_ops { ++ char* mod_name; ++ int wifi_used; ++ int sdio_id; ++ int usb_id; ++ int module_sel; ++ int (*gpio_ctrl)(char* name, int level); ++ void (*standby)(int in); ++ void (*power)(int mode, int *updown); ++ ++#ifdef CONFIG_PROC_FS ++ struct proc_dir_entry *proc_root; ++ struct proc_dir_entry *proc_power; ++#endif /* CONFIG_PROC_FS */ ++}; ++ ++static unsigned int ap6211_wl_regon = 0; ++static unsigned int ap6211_bt_regon = 0; ++static unsigned int ap6211_wl_vdd_en = 0; /*add by lemaker team for ap6211*/ ++ ++struct ap6211_gpio_wifi_ops ap6211_wifi_select_pm_ops; ++ ++char *ap6211_gpio_wifi_get_name(int module_sel) { ++ char* mod_name[] = { " ", ++ "bcm40181", /* 1 - BCM40181(BCM4330)*/ ++ "bcm40183", /* 2 - BCM40183(BCM4330)*/ ++ "rtl8723as", /* 3 - RTL8723AS(RF-SM02B) */ ++ "rtl8189es", /* 4 - RTL8189ES(SM89E00) */ ++ "rtl8192cu", /* 5 - RTL8192CU*/ ++ "rtl8188eu", /* 6 - RTL8188EU*/ ++ "ap6211", /* 7 - AP6211*/ ++ "ap6330", /* 8 - AP6330*/ ++ "ap6181", /* 9 - AP6181*/ ++ "rtl8723au", /* 10 - RTL8723AU */ ++ }; ++ ++ return(mod_name[module_sel]); ++} ++ ++EXPORT_SYMBOL(ap6211_gpio_wifi_get_name); ++ ++static int ap6211_gpio_ctrl(char* name, int level) ++{ ++ int i = 0; ++ int ret = 0; ++ int gpio = 0; ++ char * gpio_name[3] = {"ap6211_wl_regon", "ap6211_bt_regon", "ap6211_wl_vdd_en"}; /*modify by lemaker team for ap6211*/ ++ ++ for (i = 0; i < 3; i++) { ++ if (strcmp(name, gpio_name[i]) == 0) { ++ switch (i) ++ { ++ case 0: /*ap6211_wl_regon*/ ++ gpio = ap6211_wl_regon; ++ break; ++ case 1: /*ap6211_bt_regon*/ ++ gpio = ap6211_bt_regon; ++ break; ++ case 2: /*add by lemaker team for ap6211*/ ++ gpio = ap6211_wl_vdd_en; ++ break; ++ default: ++ AP6211_ERR("no matched gpio.\n" ); ++ } ++ break; ++ } ++ } ++ ++ ret = gpio_write_one_pin_value(gpio, level, name); ++ ++ if (ret) /*add by lemaker team for ap6211*/ ++ { ++ AP6211_INFO("Failed to set the gpio %s to %d\n", name, level); ++ return -1; ++ }else{ ++ AP6211_INFO("Succeed to set the gpio %s to %d\n", name, level); ++ } ++ ++ return 0; ++} ++ ++static int ap6211_gpio_read(char* name) ++{ ++ int i = 0; ++ int gpio = 0; ++ int val = 0; ++ char * gpio_name[3] = {"ap6211_wl_regon", "ap6211_bt_regon", "ap6211_wl_vdd_en"}; /*modify by lemaker team for ap6211*/ ++ ++ for (i = 0; i < 3; i++) { ++ if (strcmp(name, gpio_name[i]) == 0) { ++ switch (i) ++ { ++ case 0: /*ap6211_wl_regon*/ ++ gpio = ap6211_wl_regon; ++ break; ++ case 1: /*ap6211_bt_regon*/ ++ gpio = ap6211_bt_regon; ++ break; ++ case 2: /*add by lemaker team for ap6211*/ ++ gpio = ap6211_wl_vdd_en; ++ break; ++ default: ++ AP6211_ERR("no matched gpio.\n" ); ++ } ++ break; ++ } ++ } ++ ++ val = gpio_read_one_pin_value(gpio, name); ++ ++ return val; ++} ++ ++ ++void ap6211_power(int mode, int *updown) ++{ ++ if (mode) { ++ if (*updown) { ++ ap6211_gpio_ctrl("ap6211_wl_regon", 1); ++ mdelay(100); ++ } else { ++ ap6211_gpio_ctrl("ap6211_wl_regon", 0); ++ mdelay(100); ++ } ++ AP6211_DEBUG("sdio wifi power state: %s\n", *updown ? "on" : "off"); ++ } else { ++ *updown = ap6211_gpio_read("ap6211_wl_regon"); ++ } ++ ++ return; ++} ++/* remove by lemaker team for ap6211 ++static void ap6211_cfg_gpio_32k_clkout(int gpio_index) ++{ ++ int ret; ++ struct clk *clk_32k, *parent; ++ ++ parent = clk_get(NULL, CLK_SYS_LOSC); ++ clk_32k = clk_get(NULL, CLK_MOD_OUTA); ++ ret = clk_set_parent(clk_32k, parent); ++ ++ if(ret){ ++ AP6211_ERR("32k clk_set_parent fail.\n" ); ++ return; ++ } ++ ++ ret = clk_set_rate(clk_32k, 32768); ++ if(ret){ ++ AP6211_ERR("32k clk_set_rate fail.\n" ); ++ return; ++ } ++ ++ clk_enable(clk_32k); ++} ++*/ ++void ap6211_gpio_init(void) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ /*int ap6211_lpo = 0;*/ ++ ++/* CT expected ap6211_lpo as a GPIO */ ++/* remove by lemaker team for ap6211 ++ ap6211_lpo = gpio_request_ex(wifi_para, "ap6xxx_lpo"); ++ if (!ap6211_lpo) { ++ AP6211_ERR("request lpo gpio failed.\n" ); ++ return; ++ } ++ ++ if(ap6211_lpo) { ++ AP6211_DEBUG("config 32k clock.\n" ); ++ ap6211_cfg_gpio_32k_clkout(ap6211_lpo); ++ } ++*/ ++ ap6211_wl_regon = gpio_request_ex(wifi_para, "ap6xxx_wl_regon"); ++ if (!ap6211_wl_regon) { ++ AP6211_ERR("request wl_regon gpio failed.\n" ); ++ return; ++ } ++ /* The comment must remove when we use the Bluetooth ++ ap6211_bt_regon = gpio_request_ex(wifi_para, "ap6xxx_bt_regon"); ++ if (!ap6211_bt_regon) { ++ AP6211_ERR("request ap6211_bt_regon gpio failed.\n" ); ++ return; ++ } ++ */ ++ ++ /*add by lemaker team for ap6211*/ ++ ap6211_wl_vdd_en = gpio_request_ex(wifi_para, "ap6xxx_wl_vdd_en"); ++ if (!ap6211_wl_vdd_en) { ++ AP6211_ERR("request wl_vdd_en gpio failed.\n" ); ++ return; ++ } ++ ops->gpio_ctrl = ap6211_gpio_ctrl; ++ ops->power = ap6211_power; ++ ++ ap6211_gpio_ctrl("ap6211_wl_vdd_en", 0); /*enable the vdd*/ ++ ++} ++ ++int ap6211_gpio_wifi_get_mod_type(void) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ if (ops->wifi_used) ++ return ops->module_sel; ++ else { ++ AP6211_ERR("No wifi type selected, please check your config.\n" ); ++ return 0; ++ } ++} ++EXPORT_SYMBOL(ap6211_gpio_wifi_get_mod_type); ++ ++int ap6211_gpio_wifi_gpio_ctrl(char* name, int level) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ if (ops->wifi_used && ops->gpio_ctrl) ++ return ops->gpio_ctrl(name, level); ++ else { ++ AP6211_ERR("No wifi type selected, please check your config.\n" ); ++ return -1; ++ } ++} ++EXPORT_SYMBOL(ap6211_gpio_wifi_gpio_ctrl); ++ ++void ap6211_gpio_wifi_power(int on) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ int power = on; ++ ++ if (ops->wifi_used && ops->power) ++ return ops->power(1, &power); ++ else { ++ AP6211_ERR("No wifi type selected, please check your config.\n" ); ++ return; ++ } ++} ++EXPORT_SYMBOL(ap6211_gpio_wifi_power); ++ ++#ifdef CONFIG_PROC_FS ++static int ap6211_gpio_wifi_power_stat(char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ struct ap6211_gpio_wifi_ops *ops = (struct ap6211_gpio_wifi_ops *)data; ++ char *p = page; ++ int power = 0; ++ ++ if (ops->power) ++ ops->power(0, &power); ++ ++ p += sprintf(p, "%s : power state %s\n", ops->mod_name, power ? "on" : "off"); ++ return p - page; ++} ++ ++static int ap6211_gpio_wifi_power_ctrl(struct file *file, const char __user *buffer, unsigned long count, void *data) ++{ ++ struct ap6211_gpio_wifi_ops *ops = (struct ap6211_gpio_wifi_ops *)data; ++ int power = simple_strtoul(buffer, NULL, 10); ++ ++ power = power ? 1 : 0; ++ if (ops->power) ++ ops->power(1, &power); ++ else ++ AP6211_ERR("No power control for %s\n", ops->mod_name); ++ return sizeof(power); ++} ++ ++static inline void awwifi_procfs_attach(void) ++{ ++ char proc_rootname[] = "driver/ap6211_gpio_wifi"; ++ char proc_powername[] = "power"; ++ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ ++ ops->proc_root = proc_mkdir(proc_rootname, NULL); ++ if (IS_ERR(ops->proc_root)) ++ { ++ AP6211_ERR("failed to create procfs \"%s\".\n", proc_rootname ); ++ } ++ ++ ops->proc_power = create_proc_entry(proc_powername, 0644, ops->proc_root); ++ if (IS_ERR(ops->proc_power)) ++ { ++ AP6211_ERR("failed to create procfs \"%s\".\n", proc_powername); ++ } ++ ops->proc_power->data = ops; ++ ops->proc_power->read_proc = ap6211_gpio_wifi_power_stat; ++ ops->proc_power->write_proc = ap6211_gpio_wifi_power_ctrl; ++} ++ ++static inline void awwifi_procfs_remove(void) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ char proc_rootname[] = "driver/ap6211_gpio_wifi"; ++ ++ remove_proc_entry("power", ops->proc_root); ++ remove_proc_entry(proc_rootname, NULL); ++} ++#else ++static inline void awwifi_procfs_attach(void) {} ++static inline void awwifi_procfs_remove(void) {} ++#endif ++ ++ ++ ++static int ap6211_gpio_wifi_get_res(void) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ ++ /*add by lemaker team for AP6211*/ ++ if (SCRIPT_PARSER_OK != script_parser_fetch(wifi_para, "sdio_wifi_pro_used", &ops->wifi_used, 1)) { ++ AP6211_ERR("parse sdio_wifi_pro_used failed in script.fex.\n" ); ++ return -1; ++ } ++ if (!ops->wifi_used) { ++ AP6211_ERR("wifi pm disable in script.fex.\n" ); ++ return -1; ++ } ++ ++ /*add by lemaker team for AP6211*/ ++ if (SCRIPT_PARSER_OK != script_parser_fetch(wifi_para, "sdio_wifi_pro_sdc_id", &ops->sdio_id, 1)) { ++ AP6211_ERR("parse sdio_wifi_pro_sdc_id in script.fex failed.\n" ); ++ return -1; ++ } ++/* remove by lemaker team for AP6211 ++ if (SCRIPT_PARSER_OK != script_parser_fetch(wifi_para, "wifi_usbc_id", &ops->usb_id, 1)) { ++ AP6211_ERR("parse wifi_sdc_id in script.fex failed.\n" ); ++ return -1; ++ } ++*/ ++ /*add by lemaker team for AP6211*/ ++ if (SCRIPT_PARSER_OK != script_parser_fetch(wifi_para, "sdio_wifi_pro_mod_sel", &ops->module_sel, 1)) { ++ AP6211_ERR("parse sdio_wifi_pro_mod_sel in script.fex failed.\n" ); ++ return -1; ++ } ++ ++ ops->mod_name = ap6211_gpio_wifi_get_name(ops->module_sel); ++ ++ AP6211_ERR("select wifi %s\n", ops->mod_name); ++ ++ return 0; ++} ++ ++static int __devinit ap6211_gpio_wifi_probe(struct platform_device *pdev) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ ++ switch (ops->module_sel) { ++ case 1: /* BCM40181 */ ++ case 2: /* BCM40183 */ ++ case 3: /* RTL8723AS */ ++ case 4: /* RTL8189ES */ ++ case 5: /* RTL8192CU */ ++ case 6: /* RTL8188EU */ ++ AP6211_ERR("Unsupported device.\n"); ++ break; ++ case 7: /* AP6211 */ ++ case 8: /* AP6330 */ ++ case 9: /* AP6181 */ ++ AP6211_ERR("Initializing %s.\n", ops->mod_name); ++ ap6211_gpio_init(); ++ break; ++ case 10: /* RTL8723AU */ ++ AP6211_ERR("Unsupported device.\n"); ++ break; ++ default: ++ AP6211_ERR("Unsupported device.\n"); ++ } ++ ++ awwifi_procfs_attach(); ++ AP6211_DEBUG("wifi gpio attached.\n" ); ++ return 0; ++} ++ ++static int __devexit ap6211_gpio_wifi_remove(struct platform_device *pdev) ++{ ++ awwifi_procfs_remove(); ++ AP6211_DEBUG("wifi gpio released.\n" ); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int ap6211_gpio_wifi_suspend(struct device *dev) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ ++ if (ops->standby) ++ ops->standby(1); ++ return 0; ++} ++ ++static int ap6211_gpio_wifi_resume(struct device *dev) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ ++ if (ops->standby) ++ ops->standby(0); ++ return 0; ++} ++ ++static struct dev_pm_ops wifi_dev_pm_ops = { ++ .suspend = ap6211_gpio_wifi_suspend, ++ .resume = ap6211_gpio_wifi_resume, ++}; ++#endif ++ ++static struct platform_device ap6211_gpio_wifi_dev = { ++ .name = "ap6211_gpio_wifi", ++}; ++ ++static struct platform_driver ap6211_gpio_wifi_driver = { ++ .driver.name = "ap6211_gpio_wifi", ++ .driver.owner = THIS_MODULE, ++#ifdef CONFIG_PM ++ .driver.pm = &wifi_dev_pm_ops, ++#endif ++ .probe = ap6211_gpio_wifi_probe, ++ .remove = __devexit_p(ap6211_gpio_wifi_remove), ++}; ++ ++int __init ap6211_gpio_wifi_init(void) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ ++ memset(ops, 0, sizeof(struct ap6211_gpio_wifi_ops)); ++ ap6211_gpio_wifi_get_res(); ++ if (!ops->wifi_used) ++ return 0; ++ ++ platform_device_register(&ap6211_gpio_wifi_dev); ++ return platform_driver_register(&ap6211_gpio_wifi_driver); ++} ++ ++void __exit ap6211_gpio_wifi_exit(void) ++{ ++ struct ap6211_gpio_wifi_ops *ops = &ap6211_wifi_select_pm_ops; ++ if (!ops->wifi_used) ++ return; ++ ++ platform_driver_unregister(&ap6211_gpio_wifi_driver); ++ memset(ops, 0, sizeof(struct ap6211_gpio_wifi_ops)); ++} ++ ++/* ++module_init(ap6211_gpio_wifi_init); ++module_exit(ap6211_gpio_wifi_exit); ++ ++MODULE_LICENSE("GPL"); ++*/ +diff --git a/drivers/net/wireless/ap6211/bcmevent.c b/drivers/net/wireless/ap6211/bcmevent.c +new file mode 100755 +index 0000000..16e2fca +--- /dev/null ++++ b/drivers/net/wireless/ap6211/bcmevent.c +@@ -0,0 +1,152 @@ ++/* ++ * bcmevent read-only data shared by kernel or app layers ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * $Id: bcmevent.c 370587 2012-11-22 09:32:38Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if WLC_E_LAST != 107 ++#error "You need to add an entry to bcmevent_names[] for the new event" ++#endif ++ ++const bcmevent_name_t bcmevent_names[] = { ++ { WLC_E_SET_SSID, "SET_SSID" }, ++ { WLC_E_JOIN, "JOIN" }, ++ { WLC_E_START, "START" }, ++ { WLC_E_AUTH, "AUTH" }, ++ { WLC_E_AUTH_IND, "AUTH_IND" }, ++ { WLC_E_DEAUTH, "DEAUTH" }, ++ { WLC_E_DEAUTH_IND, "DEAUTH_IND" }, ++ { WLC_E_ASSOC, "ASSOC" }, ++ { WLC_E_ASSOC_IND, "ASSOC_IND" }, ++ { WLC_E_REASSOC, "REASSOC" }, ++ { WLC_E_REASSOC_IND, "REASSOC_IND" }, ++ { WLC_E_DISASSOC, "DISASSOC" }, ++ { WLC_E_DISASSOC_IND, "DISASSOC_IND" }, ++ { WLC_E_QUIET_START, "START_QUIET" }, ++ { WLC_E_QUIET_END, "END_QUIET" }, ++ { WLC_E_BEACON_RX, "BEACON_RX" }, ++ { WLC_E_LINK, "LINK" }, ++ { WLC_E_MIC_ERROR, "MIC_ERROR" }, ++ { WLC_E_NDIS_LINK, "NDIS_LINK" }, ++ { WLC_E_ROAM, "ROAM" }, ++ { WLC_E_TXFAIL, "TXFAIL" }, ++ { WLC_E_PMKID_CACHE, "PMKID_CACHE" }, ++ { WLC_E_RETROGRADE_TSF, "RETROGRADE_TSF" }, ++ { WLC_E_PRUNE, "PRUNE" }, ++ { WLC_E_AUTOAUTH, "AUTOAUTH" }, ++ { WLC_E_EAPOL_MSG, "EAPOL_MSG" }, ++ { WLC_E_SCAN_COMPLETE, "SCAN_COMPLETE" }, ++ { WLC_E_ADDTS_IND, "ADDTS_IND" }, ++ { WLC_E_DELTS_IND, "DELTS_IND" }, ++ { WLC_E_BCNSENT_IND, "BCNSENT_IND" }, ++ { WLC_E_BCNRX_MSG, "BCNRX_MSG" }, ++ { WLC_E_BCNLOST_MSG, "BCNLOST_IND" }, ++ { WLC_E_ROAM_PREP, "ROAM_PREP" }, ++ { WLC_E_PFN_NET_FOUND, "PFNFOUND_IND" }, ++ { WLC_E_PFN_NET_LOST, "PFNLOST_IND" }, ++#if defined(IBSS_PEER_DISCOVERY_EVENT) ++ { WLC_E_IBSS_ASSOC, "IBSS_ASSOC" }, ++#endif /* defined(IBSS_PEER_DISCOVERY_EVENT) */ ++ { WLC_E_RADIO, "RADIO" }, ++ { WLC_E_PSM_WATCHDOG, "PSM_WATCHDOG" }, ++ { WLC_E_PROBREQ_MSG, "PROBE_REQ_MSG" }, ++ { WLC_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND" }, ++ { WLC_E_PSK_SUP, "PSK_SUP" }, ++ { WLC_E_COUNTRY_CODE_CHANGED, "CNTRYCODE_IND" }, ++ { WLC_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME" }, ++ { WLC_E_ICV_ERROR, "ICV_ERROR" }, ++ { WLC_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR" }, ++ { WLC_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR" }, ++ { WLC_E_TRACE, "TRACE" }, ++#ifdef WLBTAMP ++ { WLC_E_BTA_HCI_EVENT, "BTA_HCI_EVENT" }, ++#endif ++ { WLC_E_IF, "IF" }, ++#ifdef WLP2P ++ { WLC_E_P2P_DISC_LISTEN_COMPLETE, "WLC_E_P2P_DISC_LISTEN_COMPLETE" }, ++#endif ++ { WLC_E_RSSI, "RSSI" }, ++ { WLC_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE" }, ++ { WLC_E_EXTLOG_MSG, "EXTERNAL LOG MESSAGE" }, ++#ifdef WIFI_ACT_FRAME ++ { WLC_E_ACTION_FRAME, "ACTION_FRAME" }, ++ { WLC_E_ACTION_FRAME_RX, "ACTION_FRAME_RX" }, ++ { WLC_E_ACTION_FRAME_COMPLETE, "ACTION_FRAME_COMPLETE" }, ++#endif ++#ifdef BCMWAPI_WAI ++ { WLC_E_WAI_STA_EVENT, "WAI_STA_EVENT" }, ++ { WLC_E_WAI_MSG, "WAI_MSG" }, ++#endif /* BCMWAPI_WAI */ ++#if 0 && (NDISVER >= 0x0620) ++ { WLC_E_PRE_ASSOC_IND, "ASSOC_RECV" }, ++ { WLC_E_PRE_REASSOC_IND, "REASSOC_RECV" }, ++ { WLC_E_CHANNEL_ADOPTED, "CHANNEL_ADOPTED" }, ++ { WLC_E_AP_STARTED, "AP_STARTED" }, ++ { WLC_E_DFS_AP_STOP, "DFS_AP_STOP" }, ++ { WLC_E_DFS_AP_RESUME, "DFS_AP_RESUME" }, ++ { WLC_E_ASSOC_IND_NDIS, "ASSOC_IND_NDIS"}, ++ { WLC_E_REASSOC_IND_NDIS, "REASSOC_IND_NDIS"}, ++ { WLC_E_ACTION_FRAME_RX_NDIS, "WLC_E_ACTION_FRAME_RX_NDIS" }, ++ { WLC_E_AUTH_REQ, "WLC_E_AUTH_REQ" }, ++#endif ++ { WLC_E_ESCAN_RESULT, "WLC_E_ESCAN_RESULT" }, ++ { WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, "WLC_E_AF_OFF_CHAN_COMPLETE" }, ++#ifdef WLP2P ++ { WLC_E_PROBRESP_MSG, "PROBE_RESP_MSG" }, ++ { WLC_E_P2P_PROBREQ_MSG, "P2P PROBE_REQ_MSG" }, ++#endif ++#ifdef PROP_TXSTATUS ++ { WLC_E_FIFO_CREDIT_MAP, "FIFO_CREDIT_MAP" }, ++#endif ++ { WLC_E_WAKE_EVENT, "WAKE_EVENT" }, ++ { WLC_E_DCS_REQUEST, "DCS_REQUEST" }, ++ { WLC_E_RM_COMPLETE, "RM_COMPLETE" }, ++#ifdef WLMEDIA_HTSF ++ { WLC_E_HTSFSYNC, "HTSF_SYNC_EVENT" }, ++#endif ++ { WLC_E_OVERLAY_REQ, "OVERLAY_REQ_EVENT" }, ++ { WLC_E_CSA_COMPLETE_IND, "WLC_E_CSA_COMPLETE_IND"}, ++ { WLC_E_EXCESS_PM_WAKE_EVENT, "EXCESS_PM_WAKE_EVENT" }, ++ { WLC_E_PFN_SCAN_NONE, "PFN_SCAN_NONE" }, ++ { WLC_E_PFN_SCAN_ALLGONE, "PFN_SCAN_ALLGONE" }, ++#ifdef SOFTAP ++ { WLC_E_GTK_PLUMBED, "GTK_PLUMBED" }, ++#endif ++ { WLC_E_ASSOC_REQ_IE, "ASSOC_REQ_IE" }, ++ { WLC_E_ASSOC_RESP_IE, "ASSOC_RESP_IE" }, ++ { WLC_E_ACTION_FRAME_RX_NDIS, "WLC_E_ACTION_FRAME_RX_NDIS" }, ++#ifdef WLTDLS ++ { WLC_E_TDLS_PEER_EVENT, "TDLS_PEER_EVENT" }, ++#endif /* WLTDLS */ ++ { WLC_E_SERVICE_FOUND, "SERVICE_FOUND" }, ++ { WLC_E_P2PO_ADD_DEVICE, "P2PO_DEV_FOUND" }, ++ { WLC_E_P2PO_DEL_DEVICE, "P2PO_DEV_LOST" }, ++}; ++ ++const int bcmevent_names_size = ARRAYSIZE(bcmevent_names); +diff --git a/drivers/net/wireless/ap6211/bcmsdh.c b/drivers/net/wireless/ap6211/bcmsdh.c +new file mode 100755 +index 0000000..ca59ff8 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/bcmsdh.c +@@ -0,0 +1,778 @@ ++/* ++ * BCMSDH interface glue ++ * implement bcmsdh API for SDIOH driver ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdh.c 373330 2012-12-07 04:46:17Z $ ++ */ ++ ++/** ++ * @file bcmsdh.c ++ */ ++ ++/* ****************** BCMSDH Interface Functions *************************** */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include /* BRCM API for SDIO clients (such as wl, dhd) */ ++#include /* common SDIO/controller interface */ ++#include /* SDIO device core hardware definitions. */ ++ ++#include /* SDIO Device and Protocol Specs */ ++ ++#include ++ ++#define SDIOH_API_ACCESS_RETRY_LIMIT 2 ++const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL; ++ ++/** ++ * BCMSDH API context ++ */ ++struct bcmsdh_info ++{ ++ bool init_success; /* underlying driver successfully attached */ ++ void *sdioh; /* handler for sdioh */ ++ uint32 vendevid; /* Target Vendor and Device ID on SD bus */ ++ osl_t *osh; ++ bool regfail; /* Save status of last reg_read/reg_write call */ ++ uint32 sbwad; /* Save backplane window address */ ++}; ++/* local copy of bcm sd handler */ ++bcmsdh_info_t * l_bcmsdh = NULL; ++ ++#if defined(OOB_INTR_ONLY) && defined(HW_OOB) ++extern int ++sdioh_enable_hw_oob_intr(void *sdioh, bool enable); ++ ++void ++bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable) ++{ ++ sdioh_enable_hw_oob_intr(sdh->sdioh, enable); ++} ++#endif ++ ++#if defined(HW_OOB) ++#include ++void ++bcmsdh_config_hw_oob_intr(bcmsdh_info_t *sdh, uint chip) ++{ ++ uint32 gpiocontrol, addr; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ if (CHIPID(chip) == BCM43362_CHIP_ID) { ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, gpiocontrol); ++ gpiocontrol = bcmsdh_reg_read(sdh, addr, 4); ++ gpiocontrol |= 0x2; ++ bcmsdh_reg_write(sdh, addr, 4, gpiocontrol); ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10005, 0xf, NULL); ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10006, 0x0, NULL); ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10007, 0x2, NULL); ++ } ++} ++#endif ++ ++/* Attach BCMSDH layer to SDIO Host Controller Driver ++ * ++ * @param osh OSL Handle. ++ * @param cfghdl Configuration Handle. ++ * @param regsva Virtual address of controller registers. ++ * @param irq Interrupt number of SDIO controller. ++ * ++ * @return bcmsdh_info_t Handle to BCMSDH context. ++ */ ++bcmsdh_info_t * ++bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq) ++{ ++ bcmsdh_info_t *bcmsdh; ++ ++ if ((bcmsdh = (bcmsdh_info_t *)MALLOC(osh, sizeof(bcmsdh_info_t))) == NULL) { ++ BCMSDH_ERROR(("bcmsdh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); ++ return NULL; ++ } ++ bzero((char *)bcmsdh, sizeof(bcmsdh_info_t)); ++ ++ /* save the handler locally */ ++ l_bcmsdh = bcmsdh; ++ ++ if (!(bcmsdh->sdioh = sdioh_attach(osh, cfghdl, irq))) { ++ bcmsdh_detach(osh, bcmsdh); ++ return NULL; ++ } ++ ++ bcmsdh->osh = osh; ++ bcmsdh->init_success = TRUE; ++ ++ *regsva = (uint32 *)SI_ENUM_BASE; ++ ++ /* Report the BAR, to fix if needed */ ++ bcmsdh->sbwad = SI_ENUM_BASE; ++ return bcmsdh; ++} ++ ++int ++bcmsdh_detach(osl_t *osh, void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ if (bcmsdh != NULL) { ++ if (bcmsdh->sdioh) { ++ sdioh_detach(osh, bcmsdh->sdioh); ++ bcmsdh->sdioh = NULL; ++ } ++ MFREE(osh, bcmsdh, sizeof(bcmsdh_info_t)); ++ } ++ ++ l_bcmsdh = NULL; ++ return 0; ++} ++ ++int ++bcmsdh_iovar_op(void *sdh, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ return sdioh_iovar_op(bcmsdh->sdioh, name, params, plen, arg, len, set); ++} ++ ++bool ++bcmsdh_intr_query(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ bool on; ++ ++ ASSERT(bcmsdh); ++ status = sdioh_interrupt_query(bcmsdh->sdioh, &on); ++ if (SDIOH_API_SUCCESS(status)) ++ return FALSE; ++ else ++ return on; ++} ++ ++int ++bcmsdh_intr_enable(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ASSERT(bcmsdh); ++ ++ status = sdioh_interrupt_set(bcmsdh->sdioh, TRUE); ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++int ++bcmsdh_intr_disable(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ASSERT(bcmsdh); ++ ++ status = sdioh_interrupt_set(bcmsdh->sdioh, FALSE); ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++int ++bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ASSERT(bcmsdh); ++ ++ status = sdioh_interrupt_register(bcmsdh->sdioh, fn, argh); ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++int ++bcmsdh_intr_dereg(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ASSERT(bcmsdh); ++ ++ status = sdioh_interrupt_deregister(bcmsdh->sdioh); ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++#if defined(DHD_DEBUG) ++bool ++bcmsdh_intr_pending(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ ASSERT(sdh); ++ return sdioh_interrupt_pending(bcmsdh->sdioh); ++} ++#endif ++ ++ ++int ++bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) ++{ ++ ASSERT(sdh); ++ ++ /* don't support yet */ ++ return BCME_UNSUPPORTED; ++} ++ ++/** ++ * Read from SDIO Configuration Space ++ * @param sdh SDIO Host context. ++ * @param func_num Function number to read from. ++ * @param addr Address to read from. ++ * @param err Error return. ++ * @return value read from SDIO configuration space. ++ */ ++uint8 ++bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ int32 retry = 0; ++#endif ++ uint8 data = 0; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ do { ++ if (retry) /* wait for 1 ms till bus get settled down */ ++ OSL_DELAY(1000); ++#endif ++ status = sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); ++#endif ++ if (err) ++ *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, ++ fnc_num, addr, data)); ++ ++ return data; ++} ++ ++void ++bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ int32 retry = 0; ++#endif ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ do { ++ if (retry) /* wait for 1 ms till bus get settled down */ ++ OSL_DELAY(1000); ++#endif ++ status = sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); ++#endif ++ if (err) ++ *err = SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR; ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, ++ fnc_num, addr, data)); ++} ++ ++uint32 ++bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ uint32 data = 0; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++ status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_READ, fnc_num, ++ addr, &data, 4); ++ ++ if (err) ++ *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, ++ fnc_num, addr, data)); ++ ++ return data; ++} ++ ++void ++bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++ status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, fnc_num, ++ addr, &data, 4); ++ ++ if (err) ++ *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, fnc_num, ++ addr, data)); ++} ++ ++ ++int ++bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ++ uint8 *tmp_buf, *tmp_ptr; ++ uint8 *ptr; ++ bool ascii = func & ~0xf; ++ func &= 0x7; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ASSERT(cis); ++ ASSERT(length <= SBSDIO_CIS_SIZE_LIMIT); ++ ++ status = sdioh_cis_read(bcmsdh->sdioh, func, cis, length); ++ ++ if (ascii) { ++ /* Move binary bits to tmp and format them into the provided buffer. */ ++ if ((tmp_buf = (uint8 *)MALLOC(bcmsdh->osh, length)) == NULL) { ++ BCMSDH_ERROR(("%s: out of memory\n", __FUNCTION__)); ++ return BCME_NOMEM; ++ } ++ bcopy(cis, tmp_buf, length); ++ for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4); tmp_ptr++) { ++ ptr += snprintf((char*)ptr, (cis + length - ptr - 4), ++ "%.2x ", *tmp_ptr & 0xff); ++ if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0) ++ ptr += snprintf((char *)ptr, (cis + length - ptr -4), "\n"); ++ } ++ MFREE(bcmsdh->osh, tmp_buf, length); ++ } ++ ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++ ++int ++bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set) ++{ ++ int err = 0; ++ uint bar0 = address & ~SBSDIO_SB_OFT_ADDR_MASK; ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ if (bar0 != bcmsdh->sbwad || force_set) { ++ bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, ++ (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); ++ if (!err) ++ bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, ++ (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); ++ if (!err) ++ bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, ++ (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); ++ ++ if (!err) ++ bcmsdh->sbwad = bar0; ++ else ++ /* invalidate cached window var */ ++ bcmsdh->sbwad = 0; ++ ++ } ++ ++ return err; ++} ++ ++uint32 ++bcmsdh_reg_read(void *sdh, uint32 addr, uint size) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ uint32 word = 0; ++ ++ BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, ", __FUNCTION__, addr)); ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++ if (bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)) ++ return 0xFFFFFFFF; ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ if (size == 4) ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ ++ status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, ++ SDIOH_READ, SDIO_FUNC_1, addr, &word, size); ++ ++ bcmsdh->regfail = !(SDIOH_API_SUCCESS(status)); ++ ++ BCMSDH_INFO(("uint32data = 0x%x\n", word)); ++ ++ /* if ok, return appropriately masked word */ ++ if (SDIOH_API_SUCCESS(status)) { ++ switch (size) { ++ case sizeof(uint8): ++ return (word & 0xff); ++ case sizeof(uint16): ++ return (word & 0xffff); ++ case sizeof(uint32): ++ return word; ++ default: ++ bcmsdh->regfail = TRUE; ++ ++ } ++ } ++ ++ /* otherwise, bad sdio access or invalid size */ ++ BCMSDH_ERROR(("%s: error reading addr 0x%04x size %d\n", __FUNCTION__, addr, size)); ++ return 0xFFFFFFFF; ++} ++ ++uint32 ++bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ int err = 0; ++ ++ BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n", ++ __FUNCTION__, addr, size*8, data)); ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) ++ return err; ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ if (size == 4) ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, SDIO_FUNC_1, ++ addr, &data, size); ++ bcmsdh->regfail = !(SDIOH_API_SUCCESS(status)); ++ ++ if (SDIOH_API_SUCCESS(status)) ++ return 0; ++ ++ BCMSDH_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n", ++ __FUNCTION__, data, addr, size)); ++ return 0xFFFFFFFF; ++} ++ ++bool ++bcmsdh_regfail(void *sdh) ++{ ++ return ((bcmsdh_info_t *)sdh)->regfail; ++} ++ ++int ++bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, void *pkt, ++ bcmsdh_cmplt_fn_t complete_fn, void *handle) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ uint incr_fix; ++ uint width; ++ int err = 0; ++ ++ ASSERT(bcmsdh); ++ ASSERT(bcmsdh->init_success); ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", ++ __FUNCTION__, fn, addr, nbytes)); ++ ++ /* Async not implemented yet */ ++ ASSERT(!(flags & SDIO_REQ_ASYNC)); ++ if (flags & SDIO_REQ_ASYNC) ++ return BCME_UNSUPPORTED; ++ ++ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) ++ return err; ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ ++ incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; ++ width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; ++ if (width == 4) ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ ++ status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix, ++ SDIOH_READ, fn, addr, width, nbytes, buf, pkt); ++ ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); ++} ++ ++int ++bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, void *pkt, ++ bcmsdh_cmplt_fn_t complete_fn, void *handle) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ uint incr_fix; ++ uint width; ++ int err = 0; ++ ++ ASSERT(bcmsdh); ++ ASSERT(bcmsdh->init_success); ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", ++ __FUNCTION__, fn, addr, nbytes)); ++ ++ /* Async not implemented yet */ ++ ASSERT(!(flags & SDIO_REQ_ASYNC)); ++ if (flags & SDIO_REQ_ASYNC) ++ return BCME_UNSUPPORTED; ++ ++ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) ++ return err; ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ ++ incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; ++ width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; ++ if (width == 4) ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ ++ status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix, ++ SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt); ++ ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++int ++bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ++ ASSERT(bcmsdh); ++ ASSERT(bcmsdh->init_success); ++ ASSERT((addr & SBSDIO_SBWINDOW_MASK) == 0); ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ ++ status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, SDIOH_DATA_INC, ++ (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1, ++ addr, 4, nbytes, buf, NULL); ++ ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++int ++bcmsdh_abort(void *sdh, uint fn) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ return sdioh_abort(bcmsdh->sdioh, fn); ++} ++ ++int ++bcmsdh_start(void *sdh, int stage) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ return sdioh_start(bcmsdh->sdioh, stage); ++} ++ ++int ++bcmsdh_stop(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ return sdioh_stop(bcmsdh->sdioh); ++} ++ ++int ++bcmsdh_waitlockfree(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ return sdioh_waitlockfree(bcmsdh->sdioh); ++} ++ ++ ++int ++bcmsdh_query_device(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0; ++ return (bcmsdh->vendevid); ++} ++ ++uint ++bcmsdh_query_iofnum(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ return (sdioh_query_iofnum(bcmsdh->sdioh)); ++} ++ ++int ++bcmsdh_reset(bcmsdh_info_t *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ return sdioh_sdio_reset(bcmsdh->sdioh); ++} ++ ++void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh) ++{ ++ ASSERT(sdh); ++ return sdh->sdioh; ++} ++ ++/* Function to pass device-status bits to DHD. */ ++uint32 ++bcmsdh_get_dstatus(void *sdh) ++{ ++ return 0; ++} ++uint32 ++bcmsdh_cur_sbwad(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ return (bcmsdh->sbwad); ++} ++ ++void ++bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev) ++{ ++ return; ++} ++ ++ ++int ++bcmsdh_sleep(void *sdh, bool enab) ++{ ++#ifdef SDIOH_SLEEP_ENABLED ++ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; ++ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); ++ ++ return sdioh_sleep(sd, enab); ++#else ++ return BCME_UNSUPPORTED; ++#endif ++} ++ ++int ++bcmsdh_gpio_init(void *sdh) ++{ ++ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; ++ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); ++ ++ return sdioh_gpio_init(sd); ++} ++ ++bool ++bcmsdh_gpioin(void *sdh, uint32 gpio) ++{ ++ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; ++ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); ++ ++ return sdioh_gpioin(sd, gpio); ++} ++ ++int ++bcmsdh_gpioouten(void *sdh, uint32 gpio) ++{ ++ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; ++ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); ++ ++ return sdioh_gpioouten(sd, gpio); ++} ++ ++int ++bcmsdh_gpioout(void *sdh, uint32 gpio, bool enab) ++{ ++ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; ++ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); ++ ++ return sdioh_gpioout(sd, gpio, enab); ++} ++ ++#ifdef BCMSDIOH_TXGLOM ++void ++bcmsdh_glom_post(void *sdh, uint8 *frame, uint len) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ sdioh_glom_post(bcmsdh->sdioh, frame, len); ++} ++ ++void ++bcmsdh_glom_clear(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ sdioh_glom_clear(bcmsdh->sdioh); ++} ++ ++uint ++bcmsdh_set_mode(void *sdh, uint mode) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ return (sdioh_set_mode(bcmsdh->sdioh, mode)); ++} ++ ++bool ++bcmsdh_glom_enabled(void) ++{ ++ return (sdioh_glom_enabled()); ++} ++#endif /* BCMSDIOH_TXGLOM */ +diff --git a/drivers/net/wireless/ap6211/bcmsdh_linux.c b/drivers/net/wireless/ap6211/bcmsdh_linux.c +new file mode 100755 +index 0000000..71bb3d9 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/bcmsdh_linux.c +@@ -0,0 +1,796 @@ ++/* ++ * SDIO access interface for drivers - linux specific (pci only) ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdh_linux.c 373359 2012-12-07 06:36:37Z $ ++ */ ++ ++/** ++ * @file bcmsdh_linux.c ++ */ ++ ++#define __UNDEF_NO_VERSION__ ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if defined(OOB_INTR_ONLY) ++#include ++extern void dhdsdio_isr(void * args); ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++#include ++ ++/** ++ * SDIO Host Controller info ++ */ ++typedef struct bcmsdh_hc bcmsdh_hc_t; ++ ++struct bcmsdh_hc { ++ bcmsdh_hc_t *next; ++#ifdef BCMPLATFORM_BUS ++ struct device *dev; /* platform device handle */ ++#else ++ struct pci_dev *dev; /* pci device handle */ ++#endif /* BCMPLATFORM_BUS */ ++ osl_t *osh; ++ void *regs; /* SDIO Host Controller address */ ++ bcmsdh_info_t *sdh; /* SDIO Host Controller handle */ ++ void *ch; ++ unsigned int oob_irq; ++ unsigned long oob_flags; /* OOB Host specifiction as edge and etc */ ++ bool oob_irq_registered; ++ bool oob_irq_enable_flag; ++#if defined(OOB_INTR_ONLY) ++ spinlock_t irq_lock; ++#endif ++}; ++static bcmsdh_hc_t *sdhcinfo = NULL; ++ ++/* driver info, initialized when bcmsdh_register is called */ ++static bcmsdh_driver_t drvinfo = {NULL, NULL}; ++ ++/** ++ * Checks to see if vendor and device IDs match a supported SDIO Host Controller. ++ */ ++bool ++bcmsdh_chipmatch(uint16 vendor, uint16 device) ++{ ++ /* Add other vendors and devices as required */ ++ ++#ifdef BCMSDIOH_STD ++ /* Check for Arasan host controller */ ++ if (vendor == VENDOR_SI_IMAGE) { ++ return (TRUE); ++ } ++ /* Check for BRCM 27XX Standard host controller */ ++ if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) { ++ return (TRUE); ++ } ++ /* Check for BRCM Standard host controller */ ++ if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) { ++ return (TRUE); ++ } ++ /* Check for TI PCIxx21 Standard host controller */ ++ if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) { ++ return (TRUE); ++ } ++ if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) { ++ return (TRUE); ++ } ++ /* Ricoh R5C822 Standard SDIO Host */ ++ if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) { ++ return (TRUE); ++ } ++ /* JMicron Standard SDIO Host */ ++ if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) { ++ return (TRUE); ++ } ++ ++#endif /* BCMSDIOH_STD */ ++#ifdef BCMSDIOH_SPI ++ /* This is the PciSpiHost. */ ++ if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) { ++ AP6211_ERR("Found PCI SPI Host Controller\n"); ++ return (TRUE); ++ } ++ ++#endif /* BCMSDIOH_SPI */ ++ ++ return (FALSE); ++} ++ ++#if defined(BCMPLATFORM_BUS) ++#if defined(BCMLXSDMMC) ++/* forward declarations */ ++int bcmsdh_probe(struct device *dev); ++int bcmsdh_remove(struct device *dev); ++ ++EXPORT_SYMBOL(bcmsdh_probe); ++EXPORT_SYMBOL(bcmsdh_remove); ++ ++#else ++/* forward declarations */ ++static int __devinit bcmsdh_probe(struct device *dev); ++static int __devexit bcmsdh_remove(struct device *dev); ++#endif ++ ++#if !defined(BCMLXSDMMC) ++static ++#endif ++int bcmsdh_probe(struct device *dev) ++{ ++ osl_t *osh = NULL; ++ bcmsdh_hc_t *sdhc = NULL; ++ ulong regs = 0; ++ bcmsdh_info_t *sdh = NULL; ++#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) ++ struct platform_device *pdev; ++ struct resource *r; ++#endif ++ int irq = 0; ++ uint32 vendevid; ++ unsigned long irq_flags = 0; ++ ++#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) ++ pdev = to_platform_device(dev); ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ irq = platform_get_irq(pdev, 0); ++ if (!r || irq == NO_IRQ) ++ return -ENXIO; ++#endif ++ ++#if defined(OOB_INTR_ONLY) ++#ifdef HW_OOB ++ irq_flags = ++ IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; ++#else ++ irq_flags = IRQF_TRIGGER_FALLING; ++#endif /* HW_OOB */ ++ ++ /* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */ ++ irq = dhd_customer_oob_irq_map(&irq_flags); ++#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) ++ /* Do not disable this IRQ during suspend */ ++ irq_flags |= IRQF_NO_SUSPEND; ++#endif /* defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) */ ++ if (irq < 0) { ++ AP6211_ERR("%s: Host irq is not defined\n", __FUNCTION__); ++ return 1; ++ } ++#endif ++ /* allocate SDIO Host Controller state info */ ++ if (!(osh = osl_attach(dev, PCI_BUS, FALSE))) { ++ AP6211_ERR("%s: osl_attach failed\n", __FUNCTION__); ++ goto err; ++ } ++ if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) { ++ AP6211_ERR("%s: out of memory, allocated %d bytes\n", ++ __FUNCTION__, ++ MALLOCED(osh)); ++ goto err; ++ } ++ bzero(sdhc, sizeof(bcmsdh_hc_t)); ++ sdhc->osh = osh; ++ ++ sdhc->dev = (void *)dev; ++ ++#if defined(BCMLXSDMMC) ++ if (!(sdh = bcmsdh_attach(osh, (void *)0, ++ (void **)®s, irq))) { ++ AP6211_ERR("%s: bcmsdh_attach failed\n", __FUNCTION__); ++ goto err; ++ } ++#else ++ if (!(sdh = bcmsdh_attach(osh, (void *)r->start, ++ (void **)®s, irq))) { ++ AP6211_ERR("%s: bcmsdh_attach failed\n", __FUNCTION__); ++ goto err; ++ } ++#endif ++ sdhc->sdh = sdh; ++ sdhc->oob_irq = irq; ++ sdhc->oob_flags = irq_flags; ++ sdhc->oob_irq_registered = FALSE; /* to make sure.. */ ++ sdhc->oob_irq_enable_flag = FALSE; ++#if defined(OOB_INTR_ONLY) ++ spin_lock_init(&sdhc->irq_lock); ++#endif ++ ++ /* chain SDIO Host Controller info together */ ++ sdhc->next = sdhcinfo; ++ sdhcinfo = sdhc; ++ ++ /* Read the vendor/device ID from the CIS */ ++ vendevid = bcmsdh_query_device(sdh); ++ /* try to attach to the target device */ ++ if (!(sdhc->ch = drvinfo.attach((vendevid >> 16), ++ (vendevid & 0xFFFF), 0, 0, 0, 0, ++ (void *)regs, NULL, sdh))) { ++ AP6211_ERR("%s: device attach failed\n", __FUNCTION__); ++ goto err; ++ } ++ ++ return 0; ++ ++ /* error handling */ ++err: ++ if (sdhc) { ++ if (sdhc->sdh) ++ bcmsdh_detach(sdhc->osh, sdhc->sdh); ++ MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); ++ } ++ if (osh) ++ osl_detach(osh); ++ return -ENODEV; ++} ++ ++#if !defined(BCMLXSDMMC) ++static ++#endif ++int bcmsdh_remove(struct device *dev) ++{ ++ bcmsdh_hc_t *sdhc, *prev; ++ osl_t *osh; ++ ++ sdhc = sdhcinfo; ++ drvinfo.detach(sdhc->ch); ++ bcmsdh_detach(sdhc->osh, sdhc->sdh); ++ ++ /* find the SDIO Host Controller state for this pdev and take it out from the list */ ++ for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) { ++ if (sdhc->dev == (void *)dev) { ++ if (prev) ++ prev->next = sdhc->next; ++ else ++ sdhcinfo = NULL; ++ break; ++ } ++ prev = sdhc; ++ } ++ if (!sdhc) { ++ AP6211_ERR("%s: failed\n", __FUNCTION__); ++ return 0; ++ } ++ ++ /* release SDIO Host Controller info */ ++ osh = sdhc->osh; ++ MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); ++ osl_detach(osh); ++ ++#if !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY) ++ dev_set_drvdata(dev, NULL); ++#endif ++ ++ return 0; ++} ++ ++#else /* BCMPLATFORM_BUS */ ++ ++#if !defined(BCMLXSDMMC) ++/* forward declarations for PCI probe and remove functions. */ ++static int __devinit bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); ++static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev); ++ ++/** ++ * pci id table ++ */ ++static struct pci_device_id bcmsdh_pci_devid[] __devinitdata = { ++ { vendor: PCI_ANY_ID, ++ device: PCI_ANY_ID, ++ subvendor: PCI_ANY_ID, ++ subdevice: PCI_ANY_ID, ++ class: 0, ++ class_mask: 0, ++ driver_data: 0, ++ }, ++ { 0, } ++}; ++MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid); ++ ++/** ++ * SDIO Host Controller pci driver info ++ */ ++static struct pci_driver bcmsdh_pci_driver = { ++ node: {}, ++ name: "bcmsdh", ++ id_table: bcmsdh_pci_devid, ++ probe: bcmsdh_pci_probe, ++ remove: bcmsdh_pci_remove, ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++ save_state: NULL, ++#endif ++ suspend: NULL, ++ resume: NULL, ++ }; ++ ++ ++extern uint sd_pci_slot; /* Force detection to a particular PCI */ ++ /* slot only . Allows for having multiple */ ++ /* WL devices at once in a PC */ ++ /* Only one instance of dhd will be */ ++ /* usable at a time */ ++ /* Upper word is bus number, */ ++ /* lower word is slot number */ ++ /* Default value of 0xffffffff turns this */ ++ /* off */ ++module_param(sd_pci_slot, uint, 0); ++ ++ ++/** ++ * Detect supported SDIO Host Controller and attach if found. ++ * ++ * Determine if the device described by pdev is a supported SDIO Host ++ * Controller. If so, attach to it and attach to the target device. ++ */ ++static int __devinit ++bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ++{ ++ osl_t *osh = NULL; ++ bcmsdh_hc_t *sdhc = NULL; ++ ulong regs; ++ bcmsdh_info_t *sdh = NULL; ++ int rc; ++ ++ if (sd_pci_slot != 0xFFFFffff) { ++ if (pdev->bus->number != (sd_pci_slot>>16) || ++ PCI_SLOT(pdev->devfn) != (sd_pci_slot&0xffff)) { ++ AP6211_DEBUG("%s: %s: bus %X, slot %X, vend %X, dev %X\n", ++ __FUNCTION__, ++ bcmsdh_chipmatch(pdev->vendor, pdev->device) ++ ?"Found compatible SDIOHC" ++ :"Probing unknown device", ++ pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor, ++ pdev->device); ++ return -ENODEV; ++ } ++ AP6211_DEBUG("%s: %s: bus %X, slot %X, vendor %X, device %X (good PCI location)\n", ++ __FUNCTION__, ++ bcmsdh_chipmatch(pdev->vendor, pdev->device) ++ ?"Using compatible SDIOHC" ++ :"WARNING, forced use of unkown device", ++ pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor, pdev->device); ++ } ++ ++ if ((pdev->vendor == VENDOR_TI) && ((pdev->device == PCIXX21_FLASHMEDIA_ID) || ++ (pdev->device == PCIXX21_FLASHMEDIA0_ID))) { ++ uint32 config_reg; ++ ++ AP6211_ERR("%s: Disabling TI FlashMedia Controller.\n", __FUNCTION__); ++ if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) { ++ AP6211_ERR("%s: osl_attach failed\n", __FUNCTION__); ++ goto err; ++ } ++ ++ config_reg = OSL_PCI_READ_CONFIG(osh, 0x4c, 4); ++ ++ /* ++ * Set MMC_SD_DIS bit in FlashMedia Controller. ++ * Disbling the SD/MMC Controller in the FlashMedia Controller ++ * allows the Standard SD Host Controller to take over control ++ * of the SD Slot. ++ */ ++ config_reg |= 0x02; ++ OSL_PCI_WRITE_CONFIG(osh, 0x4c, 4, config_reg); ++ osl_detach(osh); ++ } ++ /* match this pci device with what we support */ ++ /* we can't solely rely on this to believe it is our SDIO Host Controller! */ ++ if (!bcmsdh_chipmatch(pdev->vendor, pdev->device)) { ++ return -ENODEV; ++ } ++ ++ /* this is a pci device we might support */ ++ AP6211_ERR("%s: Found possible SDIO Host Controller: bus %d slot %d func %d irq %d\n", ++ __FUNCTION__, ++ pdev->bus->number, PCI_SLOT(pdev->devfn), ++ PCI_FUNC(pdev->devfn), pdev->irq); ++ ++ /* use bcmsdh_query_device() to get the vendor ID of the target device so ++ * it will eventually appear in the Broadcom string on the console ++ */ ++ ++ /* allocate SDIO Host Controller state info */ ++ if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) { ++ AP6211_ERR("%s: osl_attach failed\n", __FUNCTION__); ++ goto err; ++ } ++ if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) { ++ AP6211_ERR("%s: out of memory, allocated %d bytes\n", ++ __FUNCTION__, ++ MALLOCED(osh)); ++ goto err; ++ } ++ bzero(sdhc, sizeof(bcmsdh_hc_t)); ++ sdhc->osh = osh; ++ ++ sdhc->dev = pdev; ++ ++ /* map to address where host can access */ ++ pci_set_master(pdev); ++ rc = pci_enable_device(pdev); ++ if (rc) { ++ AP6211_ERR("%s: Cannot enable PCI device\n", __FUNCTION__); ++ goto err; ++ } ++ if (!(sdh = bcmsdh_attach(osh, (void *)(uintptr)pci_resource_start(pdev, 0), ++ (void **)®s, pdev->irq))) { ++ AP6211_ERR("%s: bcmsdh_attach failed\n", __FUNCTION__); ++ goto err; ++ } ++ ++ sdhc->sdh = sdh; ++ ++ /* try to attach to the target device */ ++ if (!(sdhc->ch = drvinfo.attach(VENDOR_BROADCOM, /* pdev->vendor, */ ++ bcmsdh_query_device(sdh) & 0xFFFF, 0, 0, 0, 0, ++ (void *)regs, NULL, sdh))) { ++ AP6211_ERR("%s: device attach failed\n", __FUNCTION__); ++ goto err; ++ } ++ ++ /* chain SDIO Host Controller info together */ ++ sdhc->next = sdhcinfo; ++ sdhcinfo = sdhc; ++ ++ return 0; ++ ++ /* error handling */ ++err: ++ if (sdhc) { ++ if (sdhc->sdh) ++ bcmsdh_detach(sdhc->osh, sdhc->sdh); ++ MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); ++ } ++ if (osh) ++ osl_detach(osh); ++ return -ENODEV; ++} ++ ++ ++/** ++ * Detach from target devices and SDIO Host Controller ++ */ ++static void __devexit ++bcmsdh_pci_remove(struct pci_dev *pdev) ++{ ++ bcmsdh_hc_t *sdhc, *prev; ++ osl_t *osh; ++ ++ /* find the SDIO Host Controller state for this pdev and take it out from the list */ ++ for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) { ++ if (sdhc->dev == pdev) { ++ if (prev) ++ prev->next = sdhc->next; ++ else ++ sdhcinfo = NULL; ++ break; ++ } ++ prev = sdhc; ++ } ++ if (!sdhc) ++ return; ++ ++ drvinfo.detach(sdhc->ch); ++ ++ bcmsdh_detach(sdhc->osh, sdhc->sdh); ++ ++ /* release SDIO Host Controller info */ ++ osh = sdhc->osh; ++ MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); ++ osl_detach(osh); ++} ++#endif /* BCMLXSDMMC */ ++#endif /* BCMPLATFORM_BUS */ ++ ++extern int sdio_function_init(void); ++ ++extern int sdio_func_reg_notify(void* semaphore); ++extern void sdio_func_unreg_notify(void); ++ ++#if defined(BCMLXSDMMC) ++int bcmsdh_reg_sdio_notify(void* semaphore) ++{ ++ return sdio_func_reg_notify(semaphore); ++} ++ ++void bcmsdh_unreg_sdio_notify(void) ++{ ++ sdio_func_unreg_notify(); ++} ++#endif /* defined(BCMLXSDMMC) */ ++ ++int ++bcmsdh_register(bcmsdh_driver_t *driver) ++{ ++ int error = 0; ++ ++ drvinfo = *driver; ++ ++#if defined(BCMPLATFORM_BUS) ++ AP6211_ERR("Linux Kernel SDIO/MMC Driver\n"); ++ error = sdio_function_init(); ++ return error; ++#endif /* defined(BCMPLATFORM_BUS) */ ++ ++#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC) ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++ if (!(error = pci_module_init(&bcmsdh_pci_driver))) ++ return 0; ++#else ++ if (!(error = pci_register_driver(&bcmsdh_pci_driver))) ++ return 0; ++#endif ++ ++ AP6211_ERR("%s: pci_module_init failed 0x%x\n", __FUNCTION__, error); ++#endif /* BCMPLATFORM_BUS */ ++ ++ return error; ++} ++ ++extern void sdio_function_cleanup(void); ++ ++void ++bcmsdh_unregister(void) ++{ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++ if (bcmsdh_pci_driver.node.next) ++#endif ++ ++#if defined(BCMLXSDMMC) ++ sdio_function_cleanup(); ++#endif /* BCMLXSDMMC */ ++ ++#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC) ++ pci_unregister_driver(&bcmsdh_pci_driver); ++#endif /* BCMPLATFORM_BUS */ ++} ++ ++int bcmsdh_set_drvdata(void * dhdp) ++{ ++ AP6211_DEBUG("%s Enter \n", __FUNCTION__); ++ ++ dev_set_drvdata(sdhcinfo->dev, dhdp); ++ ++ return 0; ++} ++ ++#if defined(OOB_INTR_ONLY) ++#define CONFIG_ARCH_SUN6I_AP6211 1 ++ ++void bcmsdh_oob_intr_set(bool enable) ++{ ++ static bool curstate = 1; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&sdhcinfo->irq_lock, flags); ++ if (curstate != enable) { ++ if(enable) { ++ enable_irq(sdhcinfo->oob_irq); ++ } ++ else { ++ disable_irq_nosync(sdhcinfo->oob_irq); ++ } ++ curstate = enable; ++ } ++ ++ spin_unlock_irqrestore(&sdhcinfo->irq_lock, flags); ++} ++ ++static irqreturn_t wlan_oob_irq(int irq, void *dev_id) ++{ ++ dhd_pub_t *dhdp; ++ ++ dhdp = (dhd_pub_t *)dev_get_drvdata(sdhcinfo->dev); ++ ++ bcmsdh_oob_intr_set(0); ++ ++ if (dhdp == NULL) { ++ AP6211_ERR("Out of band GPIO interrupt fired way too early\n"); ++ return IRQ_HANDLED; ++ } ++ ++ dhdsdio_isr((void *)dhdp->bus); ++ ++ return IRQ_HANDLED; ++} ++ ++extern int wl_host_wake_irqno; ++irqreturn_t bcmdhd_gpio_irq_handler(int irq, void *dev) ++{ ++ wlan_oob_irq(0, NULL); ++ return IRQ_HANDLED; ++} ++ ++int bcmsdh_register_oob_intr(void * dhdp) ++{ ++ int error = 0; ++ int ret; ++ AP6211_DEBUG("%s Enter \n", __FUNCTION__); ++ ++ /* IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; */ ++ dev_set_drvdata(sdhcinfo->dev, dhdp); ++ ++ if (!sdhcinfo->oob_irq_registered) { ++ AP6211_DEBUG("%s IRQ=%d Type=%X \n", __FUNCTION__, ++ (int)sdhcinfo->oob_irq, (int)sdhcinfo->oob_flags); ++ ++ ret = request_irq(wl_host_wake_irqno, bcmdhd_gpio_irq_handler, IRQF_DISABLED| IRQF_SHARED| IRQF_TRIGGER_HIGH, "bcmdhd_gpio_irq", (void *)&wl_host_wake_irqno); ++ if (ret) { ++ AP6211_ERR("request irq%d failed\n", wl_host_wake_irqno); ++ return -1; ++ } ++ ++#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) || defined(CONFIG_ARCH_SUN6I_AP6211) ++ if (device_may_wakeup(sdhcinfo->dev)) { ++#endif ++ error = enable_irq_wake(sdhcinfo->oob_irq); ++#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) || defined(CONFIG_ARCH_SUN6I_AP6211) ++ } ++#endif ++ if (error) ++ AP6211_ERR("%s enable_irq_wake error=%d \n", __FUNCTION__, error); ++ sdhcinfo->oob_irq_registered = TRUE; ++ sdhcinfo->oob_irq_enable_flag = TRUE; ++ } ++ ++ return 0; ++} ++ ++void bcmsdh_set_irq(int flag) ++{ ++ if (sdhcinfo->oob_irq_registered && sdhcinfo->oob_irq_enable_flag != flag) { ++ AP6211_ERR("%s Flag = %d\n", __FUNCTION__, flag); ++ sdhcinfo->oob_irq_enable_flag = flag; ++ if (flag) { ++ enable_irq(sdhcinfo->oob_irq); ++ ++#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) || defined(CONFIG_ARCH_SUN6I_AP6211) ++ if (device_may_wakeup(sdhcinfo->dev)) ++#endif ++ enable_irq_wake(sdhcinfo->oob_irq); ++ } else { ++#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) || defined(CONFIG_ARCH_SUN6I_AP6211) ++ if (device_may_wakeup(sdhcinfo->dev)) ++#endif ++ disable_irq_wake(sdhcinfo->oob_irq); ++ ++ ++ disable_irq(sdhcinfo->oob_irq); ++ } ++ } ++} ++ ++void bcmsdh_unregister_oob_intr(void) ++{ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (sdhcinfo->oob_irq_registered == TRUE) { ++ ++ if(0 != wl_host_wake_irqno) { ++ AP6211_DEBUG("free_irq %d\n", wl_host_wake_irqno); ++ free_irq(wl_host_wake_irqno, &wl_host_wake_irqno); ++ } ++ ++ sdhcinfo->oob_irq_registered = FALSE; ++ } ++} ++#endif ++ ++#if defined(BCMLXSDMMC) ++void *bcmsdh_get_drvdata(void) ++{ ++ if (!sdhcinfo) ++ return NULL; ++ return dev_get_drvdata(sdhcinfo->dev); ++} ++#endif ++ ++/* Module parameters specific to each host-controller driver */ ++ ++extern uint sd_msglevel; /* Debug message level */ ++module_param(sd_msglevel, uint, 0); ++ ++extern uint sd_power; /* 0 = SD Power OFF, 1 = SD Power ON. */ ++module_param(sd_power, uint, 0); ++ ++extern uint sd_clock; /* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */ ++module_param(sd_clock, uint, 0); ++ ++extern uint sd_divisor; /* Divisor (-1 means external clock) */ ++module_param(sd_divisor, uint, 0); ++ ++extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */ ++module_param(sd_sdmode, uint, 0); ++ ++extern uint sd_hiok; /* Ok to use hi-speed mode */ ++module_param(sd_hiok, uint, 0); ++ ++extern uint sd_f2_blocksize; ++module_param(sd_f2_blocksize, int, 0); ++ ++#ifdef BCMSDIOH_STD ++extern int sd_uhsimode; ++module_param(sd_uhsimode, int, 0); ++#endif ++ ++#ifdef BCMSDIOH_TXGLOM ++extern uint sd_txglom; ++module_param(sd_txglom, uint, 0); ++#endif ++ ++#ifdef BCMSDH_MODULE ++EXPORT_SYMBOL(bcmsdh_attach); ++EXPORT_SYMBOL(bcmsdh_detach); ++EXPORT_SYMBOL(bcmsdh_intr_query); ++EXPORT_SYMBOL(bcmsdh_intr_enable); ++EXPORT_SYMBOL(bcmsdh_intr_disable); ++EXPORT_SYMBOL(bcmsdh_intr_reg); ++EXPORT_SYMBOL(bcmsdh_intr_dereg); ++ ++#if defined(DHD_DEBUG) ++EXPORT_SYMBOL(bcmsdh_intr_pending); ++#endif ++ ++EXPORT_SYMBOL(bcmsdh_devremove_reg); ++EXPORT_SYMBOL(bcmsdh_cfg_read); ++EXPORT_SYMBOL(bcmsdh_cfg_write); ++EXPORT_SYMBOL(bcmsdh_cis_read); ++EXPORT_SYMBOL(bcmsdh_reg_read); ++EXPORT_SYMBOL(bcmsdh_reg_write); ++EXPORT_SYMBOL(bcmsdh_regfail); ++EXPORT_SYMBOL(bcmsdh_send_buf); ++EXPORT_SYMBOL(bcmsdh_recv_buf); ++ ++EXPORT_SYMBOL(bcmsdh_rwdata); ++EXPORT_SYMBOL(bcmsdh_abort); ++EXPORT_SYMBOL(bcmsdh_query_device); ++EXPORT_SYMBOL(bcmsdh_query_iofnum); ++EXPORT_SYMBOL(bcmsdh_iovar_op); ++EXPORT_SYMBOL(bcmsdh_register); ++EXPORT_SYMBOL(bcmsdh_unregister); ++EXPORT_SYMBOL(bcmsdh_chipmatch); ++EXPORT_SYMBOL(bcmsdh_reset); ++EXPORT_SYMBOL(bcmsdh_waitlockfree); ++ ++EXPORT_SYMBOL(bcmsdh_get_dstatus); ++EXPORT_SYMBOL(bcmsdh_cfg_read_word); ++EXPORT_SYMBOL(bcmsdh_cfg_write_word); ++EXPORT_SYMBOL(bcmsdh_cur_sbwad); ++EXPORT_SYMBOL(bcmsdh_chipinfo); ++ ++#endif /* BCMSDH_MODULE */ +diff --git a/drivers/net/wireless/ap6211/bcmsdh_sdmmc.c b/drivers/net/wireless/ap6211/bcmsdh_sdmmc.c +new file mode 100755 +index 0000000..5f0d300 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/bcmsdh_sdmmc.c +@@ -0,0 +1,1532 @@ ++/* ++ * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdh_sdmmc.c 362913 2012-10-15 11:26:11Z $ ++ */ ++#include ++ ++#include ++#include ++#include ++#include ++#include /* SDIO Device and Protocol Specs */ ++#include /* Standard SDIO Host Controller Specification */ ++#include /* bcmsdh to/from specific controller APIs */ ++#include /* ioctl/iovars */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) ++#include ++extern volatile bool dhd_mmc_suspend; ++#endif ++#include "bcmsdh_sdmmc.h" ++ ++#include ++ ++#ifndef BCMSDH_MODULE ++extern int sdio_function_init(void); ++extern void sdio_function_cleanup(void); ++#endif /* BCMSDH_MODULE */ ++ ++#if !defined(OOB_INTR_ONLY) ++static void IRQHandler(struct sdio_func *func); ++static void IRQHandlerF2(struct sdio_func *func); ++#endif /* !defined(OOB_INTR_ONLY) */ ++static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr); ++extern int sdio_reset_comm(struct mmc_card *card); ++extern int sw_mci_check_r1_ready(struct mmc_host* mmc, unsigned ms); ++ ++extern PBCMSDH_SDMMC_INSTANCE gInstance; ++ ++#define DEFAULT_SDIO_F2_BLKSIZE 512 ++#ifndef CUSTOM_SDIO_F2_BLKSIZE ++#define CUSTOM_SDIO_F2_BLKSIZE DEFAULT_SDIO_F2_BLKSIZE ++#endif ++ ++uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ ++uint sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE; ++uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */ ++ ++uint sd_power = 1; /* Default to SD Slot powered ON */ ++uint sd_clock = 1; /* Default to SD Clock turned ON */ ++uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */ ++uint sd_msglevel = 0x01; ++uint sd_use_dma = TRUE; ++DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait); ++DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait); ++DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait); ++DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait); ++ ++#define DMA_ALIGN_MASK 0x03 ++#define MMC_SDIO_ABORT_RETRY_LIMIT 5 ++ ++int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data); ++ ++static int ++sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd) ++{ ++ int err_ret; ++ uint32 fbraddr; ++ uint8 func; ++ ++ AP6211_DEBUG("%s\n", __FUNCTION__);; ++ ++ /* Get the Card's common CIS address */ ++ sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0); ++ sd->func_cis_ptr[0] = sd->com_cis_ptr; ++ AP6211_DEBUG("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr); ++ ++ /* Get the Card's function CIS (for each function) */ ++ for (fbraddr = SDIOD_FBR_STARTADDR, func = 1; ++ func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { ++ sd->func_cis_ptr[func] = sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr); ++ AP6211_DEBUG("%s: Function %d CIS Ptr = 0x%x\n", ++ __FUNCTION__, func, sd->func_cis_ptr[func]); ++ } ++ ++ sd->func_cis_ptr[0] = sd->com_cis_ptr; ++ AP6211_DEBUG("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr); ++ ++ /* Enable Function 1 */ ++ sdio_claim_host(gInstance->func[1]); ++ err_ret = sdio_enable_func(gInstance->func[1]); ++ sdio_release_host(gInstance->func[1]); ++ if (err_ret) { ++ AP6211_ERR("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x", err_ret); ++ } ++ ++ return FALSE; ++} ++ ++/* ++ * Public entry points & extern's ++ */ ++extern sdioh_info_t * ++sdioh_attach(osl_t *osh, void *bar0, uint irq) ++{ ++ sdioh_info_t *sd; ++ int err_ret; ++ ++ AP6211_DEBUG("%s\n", __FUNCTION__); ++ ++ if (gInstance == NULL) { ++ AP6211_ERR("%s: SDIO Device not present\n", __FUNCTION__); ++ return NULL; ++ } ++ ++ if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { ++ AP6211_ERR("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)); ++ return NULL; ++ } ++ bzero((char *)sd, sizeof(sdioh_info_t)); ++ sd->osh = osh; ++ if (sdioh_sdmmc_osinit(sd) != 0) { ++ AP6211_ERR("%s:sdioh_sdmmc_osinit() failed\n", __FUNCTION__); ++ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); ++ return NULL; ++ } ++ ++ sd->num_funcs = 2; ++ sd->sd_blockmode = TRUE; ++ sd->use_client_ints = TRUE; ++ sd->client_block_size[0] = 64; ++ sd->use_rxchain = FALSE; ++ ++ gInstance->sd = sd; ++ ++ /* Claim host controller */ ++ if (gInstance->func[1]) { ++ sdio_claim_host(gInstance->func[1]); ++ ++ sd->client_block_size[1] = 64; ++ err_ret = sdio_set_block_size(gInstance->func[1], 64); ++ if (err_ret) { ++ AP6211_ERR("bcmsdh_sdmmc: Failed to set F1 blocksize\n"); ++ } ++ ++ /* Release host controller F1 */ ++ sdio_release_host(gInstance->func[1]); ++ } else { ++ AP6211_ERR("%s:gInstance->func[1] is null\n", __FUNCTION__); ++ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); ++ return NULL; ++ } ++ ++ if (gInstance->func[2]) { ++ /* Claim host controller F2 */ ++ sdio_claim_host(gInstance->func[2]); ++ ++ sd->client_block_size[2] = sd_f2_blocksize; ++ err_ret = sdio_set_block_size(gInstance->func[2], sd_f2_blocksize); ++ if (err_ret) { ++ AP6211_ERR("bcmsdh_sdmmc: Failed to set F2 blocksize to %d\n", ++ sd_f2_blocksize); ++ } ++ ++ /* Release host controller F2 */ ++ sdio_release_host(gInstance->func[2]); ++ } else { ++ AP6211_ERR("%s:gInstance->func[2] is null\n", __FUNCTION__); ++ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); ++ return NULL; ++ } ++ ++ sdioh_sdmmc_card_enablefuncs(sd); ++ ++ AP6211_DEBUG("%s: Done\n", __FUNCTION__); ++ return sd; ++} ++ ++ ++extern SDIOH_API_RC ++sdioh_detach(osl_t *osh, sdioh_info_t *sd) ++{ ++ AP6211_DEBUG("%s\n", __FUNCTION__); ++ ++ if (sd) { ++ ++ /* Disable Function 2 */ ++ sdio_claim_host(gInstance->func[2]); ++ sdio_disable_func(gInstance->func[2]); ++ sdio_release_host(gInstance->func[2]); ++ ++ /* Disable Function 1 */ ++ if (gInstance->func[1]) { ++ sdio_claim_host(gInstance->func[1]); ++ sdio_disable_func(gInstance->func[1]); ++ sdio_release_host(gInstance->func[1]); ++ } ++ ++ gInstance->func[1] = NULL; ++ gInstance->func[2] = NULL; ++ ++ /* deregister irq */ ++ sdioh_sdmmc_osfree(sd); ++ ++ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); ++ } ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++#if defined(OOB_INTR_ONLY) && defined(HW_OOB) ++ ++extern SDIOH_API_RC ++sdioh_enable_func_intr(void) ++{ ++ uint8 reg; ++ int err; ++ ++ if (gInstance->func[0]) { ++ sdio_claim_host(gInstance->func[0]); ++ ++ reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err); ++ if (err) { ++ AP6211_ERR("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err); ++ sdio_release_host(gInstance->func[0]); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ /* Enable F1 and F2 interrupts, set master enable */ ++ reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN | INTR_CTL_MASTER_EN); ++ ++ sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err); ++ sdio_release_host(gInstance->func[0]); ++ ++ if (err) { ++ AP6211_ERR("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err); ++ return SDIOH_API_RC_FAIL; ++ } ++ } ++ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++extern SDIOH_API_RC ++sdioh_disable_func_intr(void) ++{ ++ uint8 reg; ++ int err; ++ ++ if (gInstance->func[0]) { ++ sdio_claim_host(gInstance->func[0]); ++ reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err); ++ if (err) { ++ AP6211_ERR("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err); ++ sdio_release_host(gInstance->func[0]); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); ++ /* Disable master interrupt with the last function interrupt */ ++ if (!(reg & 0xFE)) ++ reg = 0; ++ sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err); ++ ++ sdio_release_host(gInstance->func[0]); ++ if (err) { ++ AP6211_ERR("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err); ++ return SDIOH_API_RC_FAIL; ++ } ++ } ++ return SDIOH_API_RC_SUCCESS; ++} ++#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ ++ ++/* Configure callback to client when we recieve client interrupt */ ++extern SDIOH_API_RC ++sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) ++{ ++ AP6211_DEBUG("%s: Entering\n", __FUNCTION__); ++ if (fn == NULL) { ++ AP6211_ERR("%s: interrupt handler is NULL, not registering\n", __FUNCTION__); ++ return SDIOH_API_RC_FAIL; ++ } ++#if !defined(OOB_INTR_ONLY) ++ sd->intr_handler = fn; ++ sd->intr_handler_arg = argh; ++ sd->intr_handler_valid = TRUE; ++ ++ /* register and unmask irq */ ++ if (gInstance->func[2]) { ++ sdio_claim_host(gInstance->func[2]); ++ sdio_claim_irq(gInstance->func[2], IRQHandlerF2); ++ sdio_release_host(gInstance->func[2]); ++ } ++ ++ if (gInstance->func[1]) { ++ sdio_claim_host(gInstance->func[1]); ++ sdio_claim_irq(gInstance->func[1], IRQHandler); ++ sdio_release_host(gInstance->func[1]); ++ } ++#elif defined(HW_OOB) ++ sdioh_enable_func_intr(); ++#endif /* !defined(OOB_INTR_ONLY) */ ++ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++extern SDIOH_API_RC ++sdioh_interrupt_deregister(sdioh_info_t *sd) ++{ ++ AP6211_DEBUG("%s: Entering\n", __FUNCTION__); ++ ++#if !defined(OOB_INTR_ONLY) ++ if (gInstance->func[1]) { ++ /* register and unmask irq */ ++ sdio_claim_host(gInstance->func[1]); ++ sdio_release_irq(gInstance->func[1]); ++ sdio_release_host(gInstance->func[1]); ++ } ++ ++ if (gInstance->func[2]) { ++ /* Claim host controller F2 */ ++ sdio_claim_host(gInstance->func[2]); ++ sdio_release_irq(gInstance->func[2]); ++ /* Release host controller F2 */ ++ sdio_release_host(gInstance->func[2]); ++ } ++ ++ sd->intr_handler_valid = FALSE; ++ sd->intr_handler = NULL; ++ sd->intr_handler_arg = NULL; ++#elif defined(HW_OOB) ++ sdioh_disable_func_intr(); ++#endif /* !defined(OOB_INTR_ONLY) */ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++extern SDIOH_API_RC ++sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) ++{ ++ AP6211_DEBUG("%s: Entering\n", __FUNCTION__); ++ *onoff = sd->client_intr_enabled; ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++#if defined(DHD_DEBUG) ++extern bool ++sdioh_interrupt_pending(sdioh_info_t *sd) ++{ ++ return (0); ++} ++#endif ++ ++uint ++sdioh_query_iofnum(sdioh_info_t *sd) ++{ ++ return sd->num_funcs; ++} ++ ++/* IOVar table */ ++enum { ++ IOV_MSGLEVEL = 1, ++ IOV_BLOCKMODE, ++ IOV_BLOCKSIZE, ++ IOV_DMA, ++ IOV_USEINTS, ++ IOV_NUMINTS, ++ IOV_NUMLOCALINTS, ++ IOV_HOSTREG, ++ IOV_DEVREG, ++ IOV_DIVISOR, ++ IOV_SDMODE, ++ IOV_HISPEED, ++ IOV_HCIREGS, ++ IOV_POWER, ++ IOV_CLOCK, ++ IOV_RXCHAIN ++}; ++ ++const bcm_iovar_t sdioh_iovars[] = { ++ {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, ++ {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 }, ++ {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ ++ {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, ++ {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, ++ {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, ++ {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, ++ {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, ++ {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, ++ {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, ++ {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, ++ {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, ++ {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, ++ {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0 }, ++ {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0 }, ++ {NULL, 0, 0, 0, 0 } ++}; ++ ++int ++sdioh_iovar_op(sdioh_info_t *si, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ const bcm_iovar_t *vi = NULL; ++ int bcmerror = 0; ++ int val_size; ++ int32 int_val = 0; ++ bool bool_val; ++ uint32 actionid; ++ ++ ASSERT(name); ++ ASSERT(len >= 0); ++ ++ /* Get must have return space; Set does not take qualifiers */ ++ ASSERT(set || (arg && len)); ++ ASSERT(!set || (!params && !plen)); ++ ++ AP6211_DEBUG("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name); ++ ++ if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { ++ bcmerror = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ ++ if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) ++ goto exit; ++ ++ /* Set up params so get and set can share the convenience variables */ ++ if (params == NULL) { ++ params = arg; ++ plen = len; ++ } ++ ++ if (vi->type == IOVT_VOID) ++ val_size = 0; ++ else if (vi->type == IOVT_BUFFER) ++ val_size = len; ++ else ++ val_size = sizeof(int); ++ ++ if (plen >= (int)sizeof(int_val)) ++ bcopy(params, &int_val, sizeof(int_val)); ++ ++ bool_val = (int_val != 0) ? TRUE : FALSE; ++ BCM_REFERENCE(bool_val); ++ ++ actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); ++ switch (actionid) { ++ case IOV_GVAL(IOV_MSGLEVEL): ++ int_val = (int32)sd_msglevel; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_MSGLEVEL): ++ sd_msglevel = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_BLOCKMODE): ++ int_val = (int32)si->sd_blockmode; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_BLOCKMODE): ++ si->sd_blockmode = (bool)int_val; ++ /* Haven't figured out how to make non-block mode with DMA */ ++ break; ++ ++ case IOV_GVAL(IOV_BLOCKSIZE): ++ if ((uint32)int_val > si->num_funcs) { ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ int_val = (int32)si->client_block_size[int_val]; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_BLOCKSIZE): ++ { ++ uint func = ((uint32)int_val >> 16); ++ uint blksize = (uint16)int_val; ++ uint maxsize; ++ ++ if (func > si->num_funcs) { ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ switch (func) { ++ case 0: maxsize = 32; break; ++ case 1: maxsize = BLOCK_SIZE_4318; break; ++ case 2: maxsize = BLOCK_SIZE_4328; break; ++ default: maxsize = 0; ++ } ++ if (blksize > maxsize) { ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ if (!blksize) { ++ blksize = maxsize; ++ } ++ ++ /* Now set it */ ++ si->client_block_size[func] = blksize; ++ ++ break; ++ } ++ ++ case IOV_GVAL(IOV_RXCHAIN): ++ int_val = (int32)si->use_rxchain; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_DMA): ++ int_val = (int32)si->sd_use_dma; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DMA): ++ si->sd_use_dma = (bool)int_val; ++ break; ++ ++ case IOV_GVAL(IOV_USEINTS): ++ int_val = (int32)si->use_client_ints; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_USEINTS): ++ si->use_client_ints = (bool)int_val; ++ if (si->use_client_ints) ++ si->intmask |= CLIENT_INTR; ++ else ++ si->intmask &= ~CLIENT_INTR; ++ ++ break; ++ ++ case IOV_GVAL(IOV_DIVISOR): ++ int_val = (uint32)sd_divisor; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DIVISOR): ++ sd_divisor = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_POWER): ++ int_val = (uint32)sd_power; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_POWER): ++ sd_power = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_CLOCK): ++ int_val = (uint32)sd_clock; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_CLOCK): ++ sd_clock = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_SDMODE): ++ int_val = (uint32)sd_sdmode; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SDMODE): ++ sd_sdmode = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_HISPEED): ++ int_val = (uint32)sd_hiok; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_HISPEED): ++ sd_hiok = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_NUMINTS): ++ int_val = (int32)si->intrcount; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_NUMLOCALINTS): ++ int_val = (int32)0; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_HOSTREG): ++ { ++ sdreg_t *sd_ptr = (sdreg_t *)params; ++ ++ if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { ++ AP6211_ERR("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ AP6211_DEBUG("%s: rreg%d at offset %d\n", __FUNCTION__, ++ (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), ++ sd_ptr->offset); ++ if (sd_ptr->offset & 1) ++ int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */ ++ else if (sd_ptr->offset & 2) ++ int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */ ++ else ++ int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */ ++ ++ bcopy(&int_val, arg, sizeof(int_val)); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_HOSTREG): ++ { ++ sdreg_t *sd_ptr = (sdreg_t *)params; ++ ++ if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { ++ AP6211_ERR("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ AP6211_DEBUG("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value, ++ (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), ++ sd_ptr->offset); ++ break; ++ } ++ ++ case IOV_GVAL(IOV_DEVREG): ++ { ++ sdreg_t *sd_ptr = (sdreg_t *)params; ++ uint8 data = 0; ++ ++ if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { ++ bcmerror = BCME_SDIO_ERROR; ++ break; ++ } ++ ++ int_val = (int)data; ++ bcopy(&int_val, arg, sizeof(int_val)); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_DEVREG): ++ { ++ sdreg_t *sd_ptr = (sdreg_t *)params; ++ uint8 data = (uint8)sd_ptr->value; ++ ++ if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { ++ bcmerror = BCME_SDIO_ERROR; ++ break; ++ } ++ break; ++ } ++ ++ default: ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++exit: ++ ++ return bcmerror; ++} ++ ++#if defined(OOB_INTR_ONLY) && defined(HW_OOB) ++ ++SDIOH_API_RC ++sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable) ++{ ++ SDIOH_API_RC status; ++ uint8 data; ++ ++ if (enable) ++ data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI; ++ else ++ data = SDIO_SEPINT_ACT_HI; /* disable hw oob interrupt */ ++ ++ status = sdioh_request_byte(sd, SDIOH_WRITE, 0, SDIOD_CCCR_BRCM_SEPINT, &data); ++ return status; ++} ++#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ ++ ++extern SDIOH_API_RC ++sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) ++{ ++ SDIOH_API_RC status; ++ /* No lock needed since sdioh_request_byte does locking */ ++ status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); ++ return status; ++} ++ ++extern SDIOH_API_RC ++sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) ++{ ++ /* No lock needed since sdioh_request_byte does locking */ ++ SDIOH_API_RC status; ++ status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); ++ return status; ++} ++ ++static int ++sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr) ++{ ++ /* read 24 bits and return valid 17 bit addr */ ++ int i; ++ uint32 scratch, regdata; ++ uint8 *ptr = (uint8 *)&scratch; ++ for (i = 0; i < 3; i++) { ++ if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, ®data)) != SUCCESS) ++ AP6211_ERR("%s: Can't read!\n", __FUNCTION__); ++ ++ *ptr++ = (uint8) regdata; ++ regaddr++; ++ } ++ ++ /* Only the lower 17-bits are valid */ ++ scratch = ltoh32(scratch); ++ scratch &= 0x0001FFFF; ++ return (scratch); ++} ++ ++extern SDIOH_API_RC ++sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) ++{ ++ uint32 count; ++ int offset; ++ uint32 foo; ++ uint8 *cis = cisd; ++ ++ AP6211_DEBUG("%s: Func = %d\n", __FUNCTION__, func); ++ ++ if (!sd->func_cis_ptr[func]) { ++ bzero(cis, length); ++ AP6211_ERR("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ AP6211_ERR("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func]); ++ ++ for (count = 0; count < length; count++) { ++ offset = sd->func_cis_ptr[func] + count; ++ if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) { ++ AP6211_ERR("%s: regread failed: Can't read CIS\n", __FUNCTION__); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ *cis = (uint8)(foo & 0xff); ++ cis++; ++ } ++ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++extern SDIOH_API_RC ++sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) ++{ ++ int err_ret; ++#if defined(MMC_SDIO_ABORT) ++ int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; ++#endif ++ int ret = 0; ++ ++ AP6211_DEBUG("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr); ++ ++ DHD_PM_RESUME_WAIT(sdioh_request_byte_wait); ++ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); ++ if(rw) { /* CMD52 Write */ ++ if (func == 0) { ++ /* Can only directly write to some F0 registers. Handle F2 enable ++ * as a special case. ++ */ ++ if (regaddr == SDIOD_CCCR_IOEN) { ++ if (gInstance->func[2]) { ++ sdio_claim_host(gInstance->func[2]); ++ if (*byte & SDIO_FUNC_ENABLE_2) { ++ /* Enable Function 2 */ ++ err_ret = sdio_enable_func(gInstance->func[2]); ++ if (err_ret) { ++ AP6211_ERR("bcmsdh_sdmmc: enable F2 failed:%d", ++ err_ret); ++ } ++ } else { ++ /* Disable Function 2 */ ++ err_ret = sdio_disable_func(gInstance->func[2]); ++ if (err_ret) { ++ AP6211_ERR("bcmsdh_sdmmc: Disab F2 failed:%d", ++ err_ret); ++ } ++ } ++ sdio_release_host(gInstance->func[2]); ++ } ++ } ++#if defined(MMC_SDIO_ABORT) ++ /* to allow abort command through F1 */ ++ else if (regaddr == SDIOD_CCCR_IOABORT) { ++ /* Because of SDIO3.0 host issue on Manta, ++ * sometimes the abort fails. ++ * Retrying again will fix this issue. ++ */ ++ while (sdio_abort_retry--) { ++ if (gInstance->func[func]) { ++ sdio_claim_host(gInstance->func[func]); ++ /* ++ * this sdio_f0_writeb() can be replaced with ++ * another api depending upon MMC driver change. ++ * As of this time, this is temporaray one ++ */ ++ sdio_writeb(gInstance->func[func], ++ *byte, regaddr, &err_ret); ++ sdio_release_host(gInstance->func[func]); ++ } ++ if (!err_ret) ++ break; ++ } ++ } ++#endif /* MMC_SDIO_ABORT */ ++ else if (regaddr < 0xF0) { ++ AP6211_ERR("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr); ++ } else { ++ /* Claim host controller, perform F0 write, and release */ ++ if (gInstance->func[func]) { ++ sdio_claim_host(gInstance->func[func]); ++ sdio_f0_writeb(gInstance->func[func], ++ *byte, regaddr, &err_ret); ++ sdio_release_host(gInstance->func[func]); ++ } ++ } ++ } else { ++ /* Claim host controller, perform Fn write, and release */ ++ if (gInstance->func[func]) { ++ sdio_claim_host(gInstance->func[func]); ++ sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret); ++ sdio_release_host(gInstance->func[func]); ++ } ++ } ++ } else { /* CMD52 Read */ ++ /* Claim host controller, perform Fn read, and release */ ++ if (gInstance->func[func]) { ++ sdio_claim_host(gInstance->func[func]); ++ if (func == 0) { ++ *byte = sdio_f0_readb(gInstance->func[func], regaddr, &err_ret); ++ } else { ++ *byte = sdio_readb(gInstance->func[func], regaddr, &err_ret); ++ } ++ sdio_release_host(gInstance->func[func]); ++ } ++ } ++ ++ //AW judge sdio read write timeout, 1s ++ ret = sw_mci_check_r1_ready(gInstance->func[func]->card->host, 1000); ++ if (ret != 0) ++ AP6211_DEBUG("%s data timeout.\n", __FUNCTION__); ++ ++ if (err_ret) { ++ AP6211_ERR("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", ++ rw ? "Write" : "Read", func, regaddr, *byte, err_ret); ++ } ++ ++ return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); ++} ++ ++extern SDIOH_API_RC ++sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, ++ uint32 *word, uint nbytes) ++{ ++ int err_ret = SDIOH_API_RC_FAIL; ++#if defined(MMC_SDIO_ABORT) ++ int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; ++#endif ++ int ret = 0; ++ ++ if (func == 0) { ++ AP6211_ERR("%s: Only CMD52 allowed to F0.\n", __FUNCTION__); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ AP6211_DEBUG("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", ++ __FUNCTION__, cmd_type, rw, func, addr, nbytes); ++ ++ DHD_PM_RESUME_WAIT(sdioh_request_word_wait); ++ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); ++ /* Claim host controller */ ++ sdio_claim_host(gInstance->func[func]); ++ ++ if(rw) { /* CMD53 Write */ ++ if (nbytes == 4) { ++ sdio_writel(gInstance->func[func], *word, addr, &err_ret); ++ } else if (nbytes == 2) { ++ sdio_writew(gInstance->func[func], (*word & 0xFFFF), addr, &err_ret); ++ } else { ++ AP6211_ERR("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes); ++ } ++ } else { /* CMD52 Read */ ++ if (nbytes == 4) { ++ *word = sdio_readl(gInstance->func[func], addr, &err_ret); ++ } else if (nbytes == 2) { ++ *word = sdio_readw(gInstance->func[func], addr, &err_ret) & 0xFFFF; ++ } else { ++ AP6211_ERR("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes); ++ } ++ } ++ ++ //AW judge sdio read write timeout, 1s ++ ret = sw_mci_check_r1_ready(gInstance->func[func]->card->host, 1000); ++ if (ret != 0) ++ AP6211_DEBUG("%s data timeout.\n", __FUNCTION__); ++ ++ /* Release host controller */ ++ sdio_release_host(gInstance->func[func]); ++ ++ if (err_ret) { ++#if defined(MMC_SDIO_ABORT) ++ /* Any error on CMD53 transaction should abort that function using function 0. */ ++ while (sdio_abort_retry--) { ++ if (gInstance->func[0]) { ++ sdio_claim_host(gInstance->func[0]); ++ /* ++ * this sdio_f0_writeb() can be replaced with another api ++ * depending upon MMC driver change. ++ * As of this time, this is temporaray one ++ */ ++ sdio_writeb(gInstance->func[0], ++ func, SDIOD_CCCR_IOABORT, &err_ret); ++ sdio_release_host(gInstance->func[0]); ++ } ++ if (!err_ret) ++ break; ++ } ++ if (err_ret) ++#endif /* MMC_SDIO_ABORT */ ++ { ++ AP6211_ERR("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x\n", ++ rw ? "Write" : "Read", err_ret); ++ } ++ } ++ ++ return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); ++} ++ ++static SDIOH_API_RC ++sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, ++ uint addr, void *pkt) ++{ ++ bool fifo = (fix_inc == SDIOH_DATA_FIX); ++ uint32 SGCount = 0; ++ int err_ret = 0; ++ void *pnext, *pprev; ++ uint ttl_len, dma_len, lft_len, xfred_len, pkt_len; ++ uint blk_num; ++ int blk_size; ++ struct mmc_request mmc_req; ++ struct mmc_command mmc_cmd; ++ struct mmc_data mmc_dat; ++ int ret = 0; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ ASSERT(pkt); ++ DHD_PM_RESUME_WAIT(sdioh_request_packet_wait); ++ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); ++ ++ ttl_len = xfred_len = 0; ++ /* at least 4 bytes alignment of skb buff is guaranteed */ ++ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) ++ ttl_len += PKTLEN(sd->osh, pnext); ++ ++ blk_size = sd->client_block_size[func]; ++ if (!sd->use_rxchain || ttl_len <= blk_size) { ++ blk_num = 0; ++ dma_len = 0; ++ } else { ++ blk_num = ttl_len / blk_size; ++ dma_len = blk_num * blk_size; ++ } ++ lft_len = ttl_len - dma_len; ++ ++ AP6211_DEBUG("%s: %s %dB to func%d:%08x, %d blks with DMA, %dB leftover\n", ++ __FUNCTION__, write ? "W" : "R", ++ ttl_len, func, addr, blk_num, lft_len); ++ ++ if (0 != dma_len) { ++ memset(&mmc_req, 0, sizeof(struct mmc_request)); ++ memset(&mmc_cmd, 0, sizeof(struct mmc_command)); ++ memset(&mmc_dat, 0, sizeof(struct mmc_data)); ++ ++ /* Set up DMA descriptors */ ++ pprev = pkt; ++ for (pnext = pkt; ++ pnext && dma_len; ++ pnext = PKTNEXT(sd->osh, pnext)) { ++ pkt_len = PKTLEN(sd->osh, pnext); ++ ++ if (dma_len > pkt_len) ++ dma_len -= pkt_len; ++ else { ++ pkt_len = xfred_len = dma_len; ++ dma_len = 0; ++ pkt = pnext; ++ } ++ ++ sg_set_buf(&sd->sg_list[SGCount++], ++ (uint8*)PKTDATA(sd->osh, pnext), ++ pkt_len); ++ ++ if (SGCount >= SDIOH_SDMMC_MAX_SG_ENTRIES) { ++ AP6211_ERR("%s: sg list entries exceed limit\n", ++ __FUNCTION__); ++ return (SDIOH_API_RC_FAIL); ++ } ++ } ++ ++ mmc_dat.sg = sd->sg_list; ++ mmc_dat.sg_len = SGCount; ++ mmc_dat.blksz = blk_size; ++ mmc_dat.blocks = blk_num; ++ mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; ++ ++ mmc_cmd.opcode = 53; /* SD_IO_RW_EXTENDED */ ++ mmc_cmd.arg = write ? 1<<31 : 0; ++ mmc_cmd.arg |= (func & 0x7) << 28; ++ mmc_cmd.arg |= 1<<27; ++ mmc_cmd.arg |= fifo ? 0 : 1<<26; ++ mmc_cmd.arg |= (addr & 0x1FFFF) << 9; ++ mmc_cmd.arg |= blk_num & 0x1FF; ++ mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; ++ ++ mmc_req.cmd = &mmc_cmd; ++ mmc_req.data = &mmc_dat; ++ ++ sdio_claim_host(gInstance->func[func]); ++ mmc_set_data_timeout(&mmc_dat, gInstance->func[func]->card); ++ mmc_wait_for_req(gInstance->func[func]->card->host, &mmc_req); ++ sdio_release_host(gInstance->func[func]); ++ ++ err_ret = mmc_cmd.error? mmc_cmd.error : mmc_dat.error; ++ if (0 != err_ret) { ++ AP6211_ERR("%s:CMD53 %s failed with code %d\n", ++ __FUNCTION__, ++ write ? "write" : "read", ++ err_ret); ++ AP6211_ERR("%s:Disabling rxchain and fire it with PIO\n", ++ __FUNCTION__); ++ sd->use_rxchain = FALSE; ++ pkt = pprev; ++ lft_len = ttl_len; ++ } else if (!fifo) { ++ addr = addr + ttl_len - lft_len - dma_len; ++ } ++ } ++ ++ /* PIO mode */ ++ if (0 != lft_len) { ++ /* Claim host controller */ ++ sdio_claim_host(gInstance->func[func]); ++ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { ++ uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext) + ++ xfred_len; ++ pkt_len = PKTLEN(sd->osh, pnext); ++ if (0 != xfred_len) { ++ pkt_len -= xfred_len; ++ xfred_len = 0; ++ } ++ ++ /* Align Patch ++ * read or small packet(ex:BDC header) skip 32 byte align ++ * otherwise, padding DHD_SDALIGN for performance ++ */ ++ if (write == 0 || pkt_len < 32) ++ pkt_len = (pkt_len + 3) & 0xFFFFFFFC; ++ else if (pkt_len % blk_size) ++ pkt_len += blk_size - (pkt_len % blk_size); ++ ++#ifdef CONFIG_MMC_MSM7X00A ++ if ((pkt_len % 64) == 32) { ++ AP6211_DEBUG("%s: Rounding up TX packet +=32\n", __FUNCTION__); ++ pkt_len += 32; ++ } ++#endif /* CONFIG_MMC_MSM7X00A */ ++ ++ if ((write) && (!fifo)) ++ err_ret = sdio_memcpy_toio( ++ gInstance->func[func], ++ addr, buf, pkt_len); ++ else if (write) ++ err_ret = sdio_memcpy_toio( ++ gInstance->func[func], ++ addr, buf, pkt_len); ++ else if (fifo) ++ err_ret = sdio_readsb( ++ gInstance->func[func], ++ buf, addr, pkt_len); ++ else ++ err_ret = sdio_memcpy_fromio( ++ gInstance->func[func], ++ buf, addr, pkt_len); ++ ++ //AW judge sdio read write timeout, 1s ++ ret = sw_mci_check_r1_ready(gInstance->func[func]->card->host, 1000); ++ if (ret != 0) ++ AP6211_DEBUG("%s data timeout.\n", __FUNCTION__); ++ ++ if (err_ret) ++ AP6211_ERR("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=%d\n", ++ __FUNCTION__, ++ (write) ? "TX" : "RX", ++ pnext, SGCount, addr, pkt_len, err_ret); ++ else ++ AP6211_DEBUG("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n", ++ __FUNCTION__, ++ (write) ? "TX" : "RX", ++ pnext, SGCount, addr, pkt_len); ++ ++ if (!fifo) ++ addr += pkt_len; ++ SGCount ++; ++ } ++ sdio_release_host(gInstance->func[func]); ++ } ++ ++ AP6211_DEBUG("%s: Exit\n", __FUNCTION__); ++ return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); ++} ++ ++ ++/* ++ * This function takes a buffer or packet, and fixes everything up so that in the ++ * end, a DMA-able packet is created. ++ * ++ * A buffer does not have an associated packet pointer, and may or may not be aligned. ++ * A packet may consist of a single packet, or a packet chain. If it is a packet chain, ++ * then all the packets in the chain must be properly aligned. If the packet data is not ++ * aligned, then there may only be one packet, and in this case, it is copied to a new ++ * aligned packet. ++ * ++ */ ++extern SDIOH_API_RC ++sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func, ++ uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) ++{ ++ SDIOH_API_RC Status; ++ void *mypkt = NULL; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait); ++ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); ++ /* Case 1: we don't have a packet. */ ++ if (pkt == NULL) { ++ AP6211_DEBUG("%s: Creating new %s Packet, len=%d\n", ++ __FUNCTION__, write ? "TX" : "RX", buflen_u); ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ if (!(mypkt = PKTGET_STATIC(sd->osh, buflen_u, write ? TRUE : FALSE))) ++#else ++ if (!(mypkt = PKTGET(sd->osh, buflen_u, write ? TRUE : FALSE))) ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ { ++ AP6211_ERR("%s: PKTGET failed: len %d\n", ++ __FUNCTION__, buflen_u); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ /* For a write, copy the buffer data into the packet. */ ++ if (write) { ++ bcopy(buffer, PKTDATA(sd->osh, mypkt), buflen_u); ++ } ++ ++ Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt); ++ ++ /* For a read, copy the packet data back to the buffer. */ ++ if (!write) { ++ bcopy(PKTDATA(sd->osh, mypkt), buffer, buflen_u); ++ } ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE); ++#else ++ PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE); ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ } else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) { ++ /* Case 2: We have a packet, but it is unaligned. */ ++ ++ /* In this case, we cannot have a chain. */ ++ ASSERT(PKTNEXT(sd->osh, pkt) == NULL); ++ ++ AP6211_DEBUG("%s: Creating aligned %s Packet, len=%d\n", ++ __FUNCTION__, write ? "TX" : "RX", PKTLEN(sd->osh, pkt)); ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ if (!(mypkt = PKTGET_STATIC(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) ++#else ++ if (!(mypkt = PKTGET(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ { ++ AP6211_ERR("%s: PKTGET failed: len %d\n", ++ __FUNCTION__, PKTLEN(sd->osh, pkt)); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ /* For a write, copy the buffer data into the packet. */ ++ if (write) { ++ bcopy(PKTDATA(sd->osh, pkt), ++ PKTDATA(sd->osh, mypkt), ++ PKTLEN(sd->osh, pkt)); ++ } ++ ++ Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt); ++ ++ /* For a read, copy the packet data back to the buffer. */ ++ if (!write) { ++ bcopy(PKTDATA(sd->osh, mypkt), ++ PKTDATA(sd->osh, pkt), ++ PKTLEN(sd->osh, mypkt)); ++ } ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE); ++#else ++ PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE); ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ } else { /* case 3: We have a packet and it is aligned. */ ++ AP6211_DEBUG("%s: Aligned %s Packet, direct DMA\n", ++ __FUNCTION__, write ? "Tx" : "Rx"); ++ Status = sdioh_request_packet(sd, fix_inc, write, func, addr, pkt); ++ } ++ ++ return (Status); ++} ++ ++/* this function performs "abort" for both of host & device */ ++extern int ++sdioh_abort(sdioh_info_t *sd, uint func) ++{ ++#if defined(MMC_SDIO_ABORT) ++ char t_func = (char) func; ++#endif /* defined(MMC_SDIO_ABORT) */ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++#if defined(MMC_SDIO_ABORT) ++ /* issue abort cmd52 command through F1 */ ++ sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func); ++#endif /* defined(MMC_SDIO_ABORT) */ ++ ++ AP6211_DEBUG("%s: Exit\n", __FUNCTION__); ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++/* Reset and re-initialize the device */ ++int sdioh_sdio_reset(sdioh_info_t *si) ++{ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ AP6211_DEBUG("%s: Exit\n", __FUNCTION__); ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++/* Disable device interrupt */ ++void ++sdioh_sdmmc_devintr_off(sdioh_info_t *sd) ++{ ++ AP6211_DEBUG("%s: %d\n", __FUNCTION__, sd->use_client_ints); ++ sd->intmask &= ~CLIENT_INTR; ++} ++ ++/* Enable device interrupt */ ++void ++sdioh_sdmmc_devintr_on(sdioh_info_t *sd) ++{ ++ AP6211_DEBUG("%s: %d\n", __FUNCTION__, sd->use_client_ints); ++ sd->intmask |= CLIENT_INTR; ++} ++ ++/* Read client card reg */ ++int ++sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) ++{ ++ ++ if ((func == 0) || (regsize == 1)) { ++ uint8 temp = 0; ++ ++ sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); ++ *data = temp; ++ *data &= 0xff; ++ AP6211_DEBUG("%s: byte read data=0x%02x\n", ++ __FUNCTION__, *data); ++ } else { ++ sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize); ++ if (regsize == 2) ++ *data &= 0xffff; ++ ++ AP6211_DEBUG("%s: word read data=0x%08x\n", ++ __FUNCTION__, *data); ++ } ++ ++ return SUCCESS; ++} ++ ++#if !defined(OOB_INTR_ONLY) ++/* bcmsdh_sdmmc interrupt handler */ ++static void IRQHandler(struct sdio_func *func) ++{ ++ sdioh_info_t *sd; ++ ++ AP6211_DEBUG("bcmsdh_sdmmc: ***IRQHandler\n"); ++ sd = gInstance->sd; ++ ++ ASSERT(sd != NULL); ++ sdio_release_host(gInstance->func[0]); ++ ++ if (sd->use_client_ints) { ++ sd->intrcount++; ++ ASSERT(sd->intr_handler); ++ ASSERT(sd->intr_handler_arg); ++ (sd->intr_handler)(sd->intr_handler_arg); ++ } else { ++ AP6211_ERR("bcmsdh_sdmmc: ***IRQHandler\n"); ++ ++ AP6211_ERR("%s: Not ready for intr: enabled %d, handler %p\n", ++ __FUNCTION__, sd->client_intr_enabled, sd->intr_handler); ++ } ++ ++ sdio_claim_host(gInstance->func[0]); ++} ++ ++/* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */ ++static void IRQHandlerF2(struct sdio_func *func) ++{ ++ sdioh_info_t *sd; ++ ++ AP6211_DEBUG("bcmsdh_sdmmc: ***IRQHandlerF2\n"); ++ ++ sd = gInstance->sd; ++ ++ ASSERT(sd != NULL); ++ BCM_REFERENCE(sd); ++} ++#endif /* !defined(OOB_INTR_ONLY) */ ++ ++#ifdef NOTUSED ++/* Write client card reg */ ++static int ++sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) ++{ ++ ++ if ((func == 0) || (regsize == 1)) { ++ uint8 temp; ++ ++ temp = data & 0xff; ++ sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); ++ AP6211_DEBUG("%s: byte write data=0x%02x\n", ++ __FUNCTION__, data); ++ } else { ++ if (regsize == 2) ++ data &= 0xffff; ++ ++ sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize); ++ ++ AP6211_DEBUG("%s: word write data=0x%08x\n", ++ __FUNCTION__, data); ++ } ++ ++ return SUCCESS; ++} ++#endif /* NOTUSED */ ++ ++int ++sdioh_start(sdioh_info_t *si, int stage) ++{ ++ int ret; ++ sdioh_info_t *sd = gInstance->sd; ++ ++ if (!sd) return (0); ++ ++ /* Need to do this stages as we can't enable the interrupt till ++ downloading of the firmware is complete, other wise polling ++ sdio access will come in way ++ */ ++ if (gInstance->func[0]) { ++ if (stage == 0) { ++ /* Since the power to the chip is killed, we will have ++ re enumerate the device again. Set the block size ++ and enable the fucntion 1 for in preparation for ++ downloading the code ++ */ ++ /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux ++ 2.6.27. The implementation prior to that is buggy, and needs broadcom's ++ patch for it ++ */ ++ if ((ret = sdio_reset_comm(gInstance->func[0]->card))) { ++ AP6211_ERR("%s Failed, error = %d\n", __FUNCTION__, ret); ++ return ret; ++ } ++ else { ++ sd->num_funcs = 2; ++ sd->sd_blockmode = TRUE; ++ sd->use_client_ints = TRUE; ++ sd->client_block_size[0] = 64; ++ ++ if (gInstance->func[1]) { ++ /* Claim host controller */ ++ sdio_claim_host(gInstance->func[1]); ++ ++ sd->client_block_size[1] = 64; ++ if (sdio_set_block_size(gInstance->func[1], 64)) { ++ AP6211_ERR("bcmsdh_sdmmc: Failed to set F1 blocksize\n"); ++ } ++ ++ /* Release host controller F1 */ ++ sdio_release_host(gInstance->func[1]); ++ } ++ ++ if (gInstance->func[2]) { ++ /* Claim host controller F2 */ ++ sdio_claim_host(gInstance->func[2]); ++ ++ sd->client_block_size[2] = sd_f2_blocksize; ++ if (sdio_set_block_size(gInstance->func[2], ++ sd_f2_blocksize)) { ++ AP6211_ERR("bcmsdh_sdmmc: Failed to set F2 " ++ "blocksize to %d\n", sd_f2_blocksize); ++ } ++ ++ /* Release host controller F2 */ ++ sdio_release_host(gInstance->func[2]); ++ } ++ ++ sdioh_sdmmc_card_enablefuncs(sd); ++ } ++ } else { ++#if !defined(OOB_INTR_ONLY) ++ sdio_claim_host(gInstance->func[0]); ++ if (gInstance->func[2]) ++ sdio_claim_irq(gInstance->func[2], IRQHandlerF2); ++ if (gInstance->func[1]) ++ sdio_claim_irq(gInstance->func[1], IRQHandler); ++ sdio_release_host(gInstance->func[0]); ++#else /* defined(OOB_INTR_ONLY) */ ++#if defined(HW_OOB) ++ sdioh_enable_func_intr(); ++#endif ++ bcmsdh_oob_intr_set(TRUE); ++#endif /* !defined(OOB_INTR_ONLY) */ ++ } ++ } ++ else ++ AP6211_ERR("%s Failed\n", __FUNCTION__); ++ ++ return (0); ++} ++ ++int ++sdioh_stop(sdioh_info_t *si) ++{ ++ /* MSM7201A Android sdio stack has bug with interrupt ++ So internaly within SDIO stack they are polling ++ which cause issue when device is turned off. So ++ unregister interrupt with SDIO stack to stop the ++ polling ++ */ ++ if (gInstance->func[0]) { ++#if !defined(OOB_INTR_ONLY) ++ sdio_claim_host(gInstance->func[0]); ++ if (gInstance->func[1]) ++ sdio_release_irq(gInstance->func[1]); ++ if (gInstance->func[2]) ++ sdio_release_irq(gInstance->func[2]); ++ sdio_release_host(gInstance->func[0]); ++#else /* defined(OOB_INTR_ONLY) */ ++#if defined(HW_OOB) ++ sdioh_disable_func_intr(); ++#endif ++ bcmsdh_oob_intr_set(FALSE); ++#endif /* !defined(OOB_INTR_ONLY) */ ++ } ++ else ++ AP6211_ERR("%s Failed\n", __FUNCTION__); ++ return (0); ++} ++ ++int ++sdioh_waitlockfree(sdioh_info_t *sd) ++{ ++ return (1); ++} ++ ++ ++SDIOH_API_RC ++sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) ++{ ++ return SDIOH_API_RC_FAIL; ++} ++ ++SDIOH_API_RC ++sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) ++{ ++ return SDIOH_API_RC_FAIL; ++} ++ ++bool ++sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) ++{ ++ return FALSE; ++} ++ ++SDIOH_API_RC ++sdioh_gpio_init(sdioh_info_t *sd) ++{ ++ return SDIOH_API_RC_FAIL; ++} +diff --git a/drivers/net/wireless/ap6211/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/ap6211/bcmsdh_sdmmc_linux.c +new file mode 100755 +index 0000000..98b5818 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/bcmsdh_sdmmc_linux.c +@@ -0,0 +1,427 @@ ++/* ++ * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdh_sdmmc_linux.c 363783 2012-10-19 06:27:14Z $ ++ */ ++ ++#include ++#include ++#include /* SDIO Device and Protocol Specs */ ++#include /* bcmsdh to/from specific controller APIs */ ++#include /* to get msglevel bit values */ ++ ++#include /* request_irq() */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#if !defined(SDIO_VENDOR_ID_BROADCOM) ++#define SDIO_VENDOR_ID_BROADCOM 0x02d0 ++#endif /* !defined(SDIO_VENDOR_ID_BROADCOM) */ ++ ++#define SDIO_DEVICE_ID_BROADCOM_DEFAULT 0x0000 ++ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) ++#define SDIO_DEVICE_ID_BROADCOM_4325_SDGWB 0x0492 /* BCM94325SDGWB */ ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4325) ++#define SDIO_DEVICE_ID_BROADCOM_4325 0x0493 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4329) ++#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4319) ++#define SDIO_DEVICE_ID_BROADCOM_4319 0x4319 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4319) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4330) ++#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4330) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4334) ++#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4334) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4324) ++#define SDIO_DEVICE_ID_BROADCOM_4324 0x4324 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4324) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_43239) ++#define SDIO_DEVICE_ID_BROADCOM_43239 43239 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_43239) */ ++ ++ ++#include ++ ++#include ++ ++#ifdef WL_CFG80211 ++extern void wl_cfg80211_set_parent_dev(void *dev); ++#endif ++ ++extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); ++extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); ++extern int dhd_os_check_wakelock(void *dhdp); ++extern int dhd_os_check_if_up(void *dhdp); ++extern void *bcmsdh_get_drvdata(void); ++ ++int sdio_function_init(void); ++void sdio_function_cleanup(void); ++ ++#define DESCRIPTION "bcmsdh_sdmmc Driver" ++#define AUTHOR "Broadcom Corporation" ++ ++/* module param defaults */ ++static int clockoverride = 0; ++ ++module_param(clockoverride, int, 0644); ++MODULE_PARM_DESC(clockoverride, "SDIO card clock override"); ++ ++PBCMSDH_SDMMC_INSTANCE gInstance; ++ ++/* Maximum number of bcmsdh_sdmmc devices supported by driver */ ++#define BCMSDH_SDMMC_MAX_DEVICES 1 ++ ++extern int bcmsdh_probe(struct device *dev); ++extern int bcmsdh_remove(struct device *dev); ++extern volatile bool dhd_mmc_suspend; ++ ++static int bcmsdh_sdmmc_probe(struct sdio_func *func, ++ const struct sdio_device_id *id) ++{ ++ int ret = 0; ++ static struct sdio_func sdio_func_0; ++ ++ if (func) { ++ AP6211_DEBUG("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__); ++ AP6211_DEBUG("sdio_bcmsdh: func->class=%x\n", func->class); ++ AP6211_DEBUG("sdio_vendor: 0x%04x\n", func->vendor); ++ AP6211_DEBUG("sdio_device: 0x%04x\n", func->device); ++ AP6211_DEBUG("Function#: 0x%04x\n", func->num); ++ ++ if (func->num == 1) { ++ sdio_func_0.num = 0; ++ sdio_func_0.card = func->card; ++ gInstance->func[0] = &sdio_func_0; ++ if(func->device == 0x4) { /* 4318 */ ++ gInstance->func[2] = NULL; ++ AP6211_DEBUG("NIC found, calling bcmsdh_probe...\n"); ++ ret = bcmsdh_probe(&func->dev); ++ } ++ } ++ ++ gInstance->func[func->num] = func; ++ ++ if (func->num == 2) { ++ #ifdef WL_CFG80211 ++ wl_cfg80211_set_parent_dev(&func->dev); ++ #endif ++ AP6211_DEBUG("F2 found, calling bcmsdh_probe...\n"); ++ ret = bcmsdh_probe(&func->dev); ++ } ++ } else { ++ ret = -ENODEV; ++ } ++ ++ return ret; ++} ++ ++static void bcmsdh_sdmmc_remove(struct sdio_func *func) ++{ ++ if (func) { ++ AP6211_DEBUG("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__); ++ AP6211_DEBUG("sdio_bcmsdh: func->class=%x\n", func->class); ++ AP6211_DEBUG("sdio_vendor: 0x%04x\n", func->vendor); ++ AP6211_DEBUG("sdio_device: 0x%04x\n", func->device); ++ AP6211_DEBUG("Function#: 0x%04x\n", func->num); ++ ++ if (gInstance->func[2]) { ++ AP6211_DEBUG("F2 found, calling bcmsdh_remove...\n"); ++ bcmsdh_remove(&func->dev); ++ gInstance->func[2] = NULL; ++ } ++ if (func->num == 1) { ++ sdio_claim_host(func); ++ sdio_disable_func(func); ++ sdio_release_host(func); ++ gInstance->func[1] = NULL; ++ } ++ } ++} ++ ++/* devices we support, null terminated */ ++static const struct sdio_device_id bcmsdh_sdmmc_ids[] = { ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4324) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) }, ++ { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) }, ++ { /* end: all zeroes */ }, ++}; ++ ++MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) ++static int bcmsdh_sdmmc_suspend(struct device *pdev) ++{ ++ struct sdio_func *func = dev_to_sdio_func(pdev); ++ mmc_pm_flag_t sdio_flags; ++ int ret; ++ ++ if (func->num != 2) ++ return 0; ++ ++ AP6211_DEBUG("%s Enter\n", __FUNCTION__); ++ ++ if (dhd_os_check_wakelock(bcmsdh_get_drvdata())) ++ return -EBUSY; ++ ++ sdio_flags = sdio_get_host_pm_caps(func); ++ ++ if (!(sdio_flags & MMC_PM_KEEP_POWER)) { ++ AP6211_ERR("%s: can't keep power while host is suspended\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ /* keep power while host suspended */ ++ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); ++ if (ret) { ++ AP6211_ERR("%s: error while trying to keep power\n", __FUNCTION__); ++ return ret; ++ } ++ ++#if defined(OOB_INTR_ONLY) ++ bcmsdh_oob_intr_set(0); ++#endif /* defined(OOB_INTR_ONLY) */ ++ dhd_mmc_suspend = TRUE; ++ smp_mb(); ++ ++ return 0; ++} ++ ++static int bcmsdh_sdmmc_resume(struct device *pdev) ++{ ++#if defined(OOB_INTR_ONLY) ++ struct sdio_func *func = dev_to_sdio_func(pdev); ++#endif /* defined(OOB_INTR_ONLY) */ ++ AP6211_DEBUG("%s Enter\n", __FUNCTION__); ++ ++ dhd_mmc_suspend = FALSE; ++#if defined(OOB_INTR_ONLY) ++ if ((func->num == 2) && dhd_os_check_if_up(bcmsdh_get_drvdata())) ++ bcmsdh_oob_intr_set(1); ++#endif /* (OOB_INTR_ONLY) */ ++ smp_mb(); ++ return 0; ++} ++ ++static const struct dev_pm_ops bcmsdh_sdmmc_pm_ops = { ++ .suspend = bcmsdh_sdmmc_suspend, ++ .resume = bcmsdh_sdmmc_resume, ++}; ++#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ ++ ++#if defined(BCMLXSDMMC) ++static struct semaphore *notify_semaphore = NULL; ++ ++static int dummy_probe(struct sdio_func *func, ++ const struct sdio_device_id *id) ++{ ++ if (notify_semaphore) ++ up(notify_semaphore); ++ return 0; ++} ++ ++static void dummy_remove(struct sdio_func *func) ++{ ++} ++ ++static struct sdio_driver dummy_sdmmc_driver = { ++ .probe = dummy_probe, ++ .remove = dummy_remove, ++ .name = "dummy_sdmmc", ++ .id_table = bcmsdh_sdmmc_ids, ++ }; ++ ++int sdio_func_reg_notify(void* semaphore) ++{ ++ notify_semaphore = semaphore; ++ return sdio_register_driver(&dummy_sdmmc_driver); ++} ++ ++void sdio_func_unreg_notify(void) ++{ ++ sdio_unregister_driver(&dummy_sdmmc_driver); ++} ++ ++#endif /* defined(BCMLXSDMMC) */ ++ ++static struct sdio_driver bcmsdh_sdmmc_driver = { ++ .probe = bcmsdh_sdmmc_probe, ++ .remove = bcmsdh_sdmmc_remove, ++ .name = "bcmsdh_sdmmc", ++ .id_table = bcmsdh_sdmmc_ids, ++#if !defined(CONFIG_ARCH_RHEA) || !defined(CONFIG_ARCH_CAPRI) ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) ++ .drv = { ++ .pm = &bcmsdh_sdmmc_pm_ops, ++ }, ++#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ ++#endif /* !defined(CONFIG_ARCH_RHEA) || !defined(CONFIG_ARCH_CAPRI) */ ++ }; ++ ++struct sdos_info { ++ sdioh_info_t *sd; ++ spinlock_t lock; ++}; ++ ++ ++int ++sdioh_sdmmc_osinit(sdioh_info_t *sd) ++{ ++ struct sdos_info *sdos; ++ ++ if (!sd) ++ return BCME_BADARG; ++ ++ sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info)); ++ sd->sdos_info = (void*)sdos; ++ if (sdos == NULL) ++ return BCME_NOMEM; ++ ++ sdos->sd = sd; ++ spin_lock_init(&sdos->lock); ++ return BCME_OK; ++} ++ ++void ++sdioh_sdmmc_osfree(sdioh_info_t *sd) ++{ ++ struct sdos_info *sdos; ++ ASSERT(sd && sd->sdos_info); ++ ++ sdos = (struct sdos_info *)sd->sdos_info; ++ MFREE(sd->osh, sdos, sizeof(struct sdos_info)); ++} ++ ++/* Interrupt enable/disable */ ++SDIOH_API_RC ++sdioh_interrupt_set(sdioh_info_t *sd, bool enable) ++{ ++ ulong flags; ++ struct sdos_info *sdos; ++ ++ if (!sd) ++ return BCME_BADARG; ++ ++ AP6211_DEBUG("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling"); ++ ++ sdos = (struct sdos_info *)sd->sdos_info; ++ ASSERT(sdos); ++ ++#if !defined(OOB_INTR_ONLY) ++ if (enable && !(sd->intr_handler && sd->intr_handler_arg)) { ++ AP6211_ERR("%s: no handler registered, will not enable\n", __FUNCTION__); ++ return SDIOH_API_RC_FAIL; ++ } ++#endif /* !defined(OOB_INTR_ONLY) */ ++ ++ /* Ensure atomicity for enable/disable calls */ ++ spin_lock_irqsave(&sdos->lock, flags); ++ ++ sd->client_intr_enabled = enable; ++ if (enable) { ++ sdioh_sdmmc_devintr_on(sd); ++ } else { ++ sdioh_sdmmc_devintr_off(sd); ++ } ++ ++ spin_unlock_irqrestore(&sdos->lock, flags); ++ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++ ++#ifdef BCMSDH_MODULE ++static int __init ++bcmsdh_module_init(void) ++{ ++ int error = 0; ++ error = sdio_function_init(); ++ return error; ++} ++ ++static void __exit ++bcmsdh_module_cleanup(void) ++{ ++ sdio_function_cleanup(); ++} ++ ++module_init(bcmsdh_module_init); ++module_exit(bcmsdh_module_cleanup); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION(DESCRIPTION); ++MODULE_AUTHOR(AUTHOR); ++ ++#endif /* BCMSDH_MODULE */ ++/* ++ * module init ++*/ ++int sdio_function_init(void) ++{ ++ int error = 0; ++ AP6211_DEBUG("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__); ++ ++ gInstance = kzalloc(sizeof(BCMSDH_SDMMC_INSTANCE), GFP_KERNEL); ++ if (!gInstance) ++ return -ENOMEM; ++ ++ error = sdio_register_driver(&bcmsdh_sdmmc_driver); ++ if (error && gInstance) { ++ kfree(gInstance); ++ gInstance = 0; ++ } ++ ++ return error; ++} ++ ++/* ++ * module cleanup ++*/ ++extern int bcmsdh_remove(struct device *dev); ++void sdio_function_cleanup(void) ++{ ++ AP6211_DEBUG("%s Enter\n", __FUNCTION__); ++ ++ ++ sdio_unregister_driver(&bcmsdh_sdmmc_driver); ++ ++ if (gInstance) ++ kfree(gInstance); ++} +diff --git a/drivers/net/wireless/ap6211/bcmutils.c b/drivers/net/wireless/ap6211/bcmutils.c +new file mode 100755 +index 0000000..631125a +--- /dev/null ++++ b/drivers/net/wireless/ap6211/bcmutils.c +@@ -0,0 +1,2095 @@ ++/* ++ * Driver O/S-independent utility routines ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * $Id: bcmutils.c 312855 2012-02-04 02:01:18Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#ifdef BCMDRIVER ++ ++#include ++#include ++ ++#else /* !BCMDRIVER */ ++ ++#include ++#include ++#include ++ ++#if defined(BCMEXTSUP) ++#include ++#endif ++ ++ ++#endif /* !BCMDRIVER */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++void *_bcmutils_dummy_fn = NULL; ++ ++#include ++ ++ ++#ifdef BCMDRIVER ++ ++ ++ ++/* copy a pkt buffer chain into a buffer */ ++uint ++pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) ++{ ++ uint n, ret = 0; ++ ++ if (len < 0) ++ len = 4096; /* "infinite" */ ++ ++ /* skip 'offset' bytes */ ++ for (; p && offset; p = PKTNEXT(osh, p)) { ++ if (offset < (uint)PKTLEN(osh, p)) ++ break; ++ offset -= PKTLEN(osh, p); ++ } ++ ++ if (!p) ++ return 0; ++ ++ /* copy the data */ ++ for (; p && len; p = PKTNEXT(osh, p)) { ++ n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); ++ bcopy(PKTDATA(osh, p) + offset, buf, n); ++ buf += n; ++ len -= n; ++ ret += n; ++ offset = 0; ++ } ++ ++ return ret; ++} ++ ++/* copy a buffer into a pkt buffer chain */ ++uint ++pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf) ++{ ++ uint n, ret = 0; ++ ++ /* skip 'offset' bytes */ ++ for (; p && offset; p = PKTNEXT(osh, p)) { ++ if (offset < (uint)PKTLEN(osh, p)) ++ break; ++ offset -= PKTLEN(osh, p); ++ } ++ ++ if (!p) ++ return 0; ++ ++ /* copy the data */ ++ for (; p && len; p = PKTNEXT(osh, p)) { ++ n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); ++ bcopy(buf, PKTDATA(osh, p) + offset, n); ++ buf += n; ++ len -= n; ++ ret += n; ++ offset = 0; ++ } ++ ++ return ret; ++} ++ ++ ++ ++/* return total length of buffer chain */ ++uint BCMFASTPATH ++pkttotlen(osl_t *osh, void *p) ++{ ++ uint total; ++ int len; ++ ++ total = 0; ++ for (; p; p = PKTNEXT(osh, p)) { ++ len = PKTLEN(osh, p); ++ total += len; ++ } ++ ++ return (total); ++} ++ ++/* return the last buffer of chained pkt */ ++void * ++pktlast(osl_t *osh, void *p) ++{ ++ for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p)) ++ ; ++ ++ return (p); ++} ++ ++/* count segments of a chained packet */ ++uint BCMFASTPATH ++pktsegcnt(osl_t *osh, void *p) ++{ ++ uint cnt; ++ ++ for (cnt = 0; p; p = PKTNEXT(osh, p)) ++ cnt++; ++ ++ return cnt; ++} ++ ++ ++/* count segments of a chained packet */ ++uint BCMFASTPATH ++pktsegcnt_war(osl_t *osh, void *p) ++{ ++ uint cnt; ++ uint8 *pktdata; ++ uint len, remain, align64; ++ ++ for (cnt = 0; p; p = PKTNEXT(osh, p)) { ++ cnt++; ++ len = PKTLEN(osh, p); ++ if (len > 128) { ++ pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */ ++ /* Check for page boundary straddle (2048B) */ ++ if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff)) ++ cnt++; ++ ++ align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */ ++ align64 = (64 - align64) & 0x3f; ++ len -= align64; /* bytes from aligned 64B to end */ ++ /* if aligned to 128B, check for MOD 128 between 1 to 4B */ ++ remain = len % 128; ++ if (remain > 0 && remain <= 4) ++ cnt++; /* add extra seg */ ++ } ++ } ++ ++ return cnt; ++} ++ ++uint8 * BCMFASTPATH ++pktoffset(osl_t *osh, void *p, uint offset) ++{ ++ uint total = pkttotlen(osh, p); ++ uint pkt_off = 0, len = 0; ++ uint8 *pdata = (uint8 *) PKTDATA(osh, p); ++ ++ if (offset > total) ++ return NULL; ++ ++ for (; p; p = PKTNEXT(osh, p)) { ++ pdata = (uint8 *) PKTDATA(osh, p); ++ pkt_off = offset - len; ++ len += PKTLEN(osh, p); ++ if (len > offset) ++ break; ++ } ++ return (uint8*) (pdata+pkt_off); ++} ++ ++/* ++ * osl multiple-precedence packet queue ++ * hi_prec is always >= the number of the highest non-empty precedence ++ */ ++void * BCMFASTPATH ++pktq_penq(struct pktq *pq, int prec, void *p) ++{ ++ struct pktq_prec *q; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ ++ ++ ASSERT(!pktq_full(pq)); ++ ASSERT(!pktq_pfull(pq, prec)); ++ ++ q = &pq->q[prec]; ++ ++ if (q->head) ++ PKTSETLINK(q->tail, p); ++ else ++ q->head = p; ++ ++ q->tail = p; ++ q->len++; ++ ++ pq->len++; ++ ++ if (pq->hi_prec < prec) ++ pq->hi_prec = (uint8)prec; ++ ++ return p; ++} ++ ++void * BCMFASTPATH ++pktq_penq_head(struct pktq *pq, int prec, void *p) ++{ ++ struct pktq_prec *q; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ ++ ++ ASSERT(!pktq_full(pq)); ++ ASSERT(!pktq_pfull(pq, prec)); ++ ++ q = &pq->q[prec]; ++ ++ if (q->head == NULL) ++ q->tail = p; ++ ++ PKTSETLINK(p, q->head); ++ q->head = p; ++ q->len++; ++ ++ pq->len++; ++ ++ if (pq->hi_prec < prec) ++ pq->hi_prec = (uint8)prec; ++ ++ return p; ++} ++ ++void * BCMFASTPATH ++pktq_pdeq(struct pktq *pq, int prec) ++{ ++ struct pktq_prec *q; ++ void *p; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ return NULL; ++ ++ if ((q->head = PKTLINK(p)) == NULL) ++ q->tail = NULL; ++ ++ q->len--; ++ ++ pq->len--; ++ ++ PKTSETLINK(p, NULL); ++ ++ return p; ++} ++ ++void * BCMFASTPATH ++pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p) ++{ ++ struct pktq_prec *q; ++ void *p; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ q = &pq->q[prec]; ++ ++ if (prev_p == NULL) ++ return NULL; ++ ++ if ((p = PKTLINK(prev_p)) == NULL) ++ return NULL; ++ ++ q->len--; ++ ++ pq->len--; ++ ++ PKTSETLINK(prev_p, PKTLINK(p)); ++ PKTSETLINK(p, NULL); ++ ++ return p; ++} ++ ++void * BCMFASTPATH ++pktq_pdeq_tail(struct pktq *pq, int prec) ++{ ++ struct pktq_prec *q; ++ void *p, *prev; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ return NULL; ++ ++ for (prev = NULL; p != q->tail; p = PKTLINK(p)) ++ prev = p; ++ ++ if (prev) ++ PKTSETLINK(prev, NULL); ++ else ++ q->head = NULL; ++ ++ q->tail = prev; ++ q->len--; ++ ++ pq->len--; ++ ++ return p; ++} ++ ++void ++pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg) ++{ ++ struct pktq_prec *q; ++ void *p, *prev = NULL; ++ ++ q = &pq->q[prec]; ++ p = q->head; ++ while (p) { ++ if (fn == NULL || (*fn)(p, arg)) { ++ bool head = (p == q->head); ++ if (head) ++ q->head = PKTLINK(p); ++ else ++ PKTSETLINK(prev, PKTLINK(p)); ++ PKTSETLINK(p, NULL); ++ PKTFREE(osh, p, dir); ++ q->len--; ++ pq->len--; ++ p = (head ? q->head : PKTLINK(prev)); ++ } else { ++ prev = p; ++ p = PKTLINK(p); ++ } ++ } ++ ++ if (q->head == NULL) { ++ ASSERT(q->len == 0); ++ q->tail = NULL; ++ } ++} ++ ++bool BCMFASTPATH ++pktq_pdel(struct pktq *pq, void *pktbuf, int prec) ++{ ++ struct pktq_prec *q; ++ void *p; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ if (!pktbuf) ++ return FALSE; ++ ++ q = &pq->q[prec]; ++ ++ if (q->head == pktbuf) { ++ if ((q->head = PKTLINK(pktbuf)) == NULL) ++ q->tail = NULL; ++ } else { ++ for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p)) ++ ; ++ if (p == NULL) ++ return FALSE; ++ ++ PKTSETLINK(p, PKTLINK(pktbuf)); ++ if (q->tail == pktbuf) ++ q->tail = p; ++ } ++ ++ q->len--; ++ pq->len--; ++ PKTSETLINK(pktbuf, NULL); ++ return TRUE; ++} ++ ++void ++pktq_init(struct pktq *pq, int num_prec, int max_len) ++{ ++ int prec; ++ ++ ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC); ++ ++ /* pq is variable size; only zero out what's requested */ ++ bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec)); ++ ++ pq->num_prec = (uint16)num_prec; ++ ++ pq->max = (uint16)max_len; ++ ++ for (prec = 0; prec < num_prec; prec++) ++ pq->q[prec].max = pq->max; ++} ++ ++void ++pktq_set_max_plen(struct pktq *pq, int prec, int max_len) ++{ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ if (prec < pq->num_prec) ++ pq->q[prec].max = (uint16)max_len; ++} ++ ++void * BCMFASTPATH ++pktq_deq(struct pktq *pq, int *prec_out) ++{ ++ struct pktq_prec *q; ++ void *p; ++ int prec; ++ ++ if (pq->len == 0) ++ return NULL; ++ ++ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) ++ pq->hi_prec--; ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ return NULL; ++ ++ if ((q->head = PKTLINK(p)) == NULL) ++ q->tail = NULL; ++ ++ q->len--; ++ ++ pq->len--; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ PKTSETLINK(p, NULL); ++ ++ return p; ++} ++ ++void * BCMFASTPATH ++pktq_deq_tail(struct pktq *pq, int *prec_out) ++{ ++ struct pktq_prec *q; ++ void *p, *prev; ++ int prec; ++ ++ if (pq->len == 0) ++ return NULL; ++ ++ for (prec = 0; prec < pq->hi_prec; prec++) ++ if (pq->q[prec].head) ++ break; ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ return NULL; ++ ++ for (prev = NULL; p != q->tail; p = PKTLINK(p)) ++ prev = p; ++ ++ if (prev) ++ PKTSETLINK(prev, NULL); ++ else ++ q->head = NULL; ++ ++ q->tail = prev; ++ q->len--; ++ ++ pq->len--; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ PKTSETLINK(p, NULL); ++ ++ return p; ++} ++ ++void * ++pktq_peek(struct pktq *pq, int *prec_out) ++{ ++ int prec; ++ ++ if (pq->len == 0) ++ return NULL; ++ ++ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) ++ pq->hi_prec--; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ return (pq->q[prec].head); ++} ++ ++void * ++pktq_peek_tail(struct pktq *pq, int *prec_out) ++{ ++ int prec; ++ ++ if (pq->len == 0) ++ return NULL; ++ ++ for (prec = 0; prec < pq->hi_prec; prec++) ++ if (pq->q[prec].head) ++ break; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ return (pq->q[prec].tail); ++} ++ ++void ++pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg) ++{ ++ int prec; ++ ++ /* Optimize flush, if pktq len = 0, just return. ++ * pktq len of 0 means pktq's prec q's are all empty. ++ */ ++ if (pq->len == 0) { ++ return; ++ } ++ ++ for (prec = 0; prec < pq->num_prec; prec++) ++ pktq_pflush(osh, pq, prec, dir, fn, arg); ++ if (fn == NULL) ++ ASSERT(pq->len == 0); ++} ++ ++/* Return sum of lengths of a specific set of precedences */ ++int ++pktq_mlen(struct pktq *pq, uint prec_bmp) ++{ ++ int prec, len; ++ ++ len = 0; ++ ++ for (prec = 0; prec <= pq->hi_prec; prec++) ++ if (prec_bmp & (1 << prec)) ++ len += pq->q[prec].len; ++ ++ return len; ++} ++ ++/* Priority peek from a specific set of precedences */ ++void * BCMFASTPATH ++pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out) ++{ ++ struct pktq_prec *q; ++ void *p; ++ int prec; ++ ++ if (pq->len == 0) ++ { ++ return NULL; ++ } ++ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) ++ pq->hi_prec--; ++ ++ while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL) ++ if (prec-- == 0) ++ return NULL; ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ return NULL; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ return p; ++} ++/* Priority dequeue from a specific set of precedences */ ++void * BCMFASTPATH ++pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) ++{ ++ struct pktq_prec *q; ++ void *p; ++ int prec; ++ ++ if (pq->len == 0) ++ return NULL; ++ ++ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) ++ pq->hi_prec--; ++ ++ while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0)) ++ if (prec-- == 0) ++ return NULL; ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ return NULL; ++ ++ if ((q->head = PKTLINK(p)) == NULL) ++ q->tail = NULL; ++ ++ q->len--; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ pq->len--; ++ ++ PKTSETLINK(p, NULL); ++ ++ return p; ++} ++ ++#endif /* BCMDRIVER */ ++ ++const unsigned char bcm_ctype[] = { ++ ++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */ ++ _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C, ++ _BCM_C, /* 8-15 */ ++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */ ++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */ ++ _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */ ++ _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */ ++ _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */ ++ _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */ ++ _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, ++ _BCM_U|_BCM_X, _BCM_U, /* 64-71 */ ++ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */ ++ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */ ++ _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */ ++ _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, ++ _BCM_L|_BCM_X, _BCM_L, /* 96-103 */ ++ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */ ++ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */ ++ _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */ ++ _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, ++ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */ ++ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, ++ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */ ++ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, ++ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */ ++ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U, ++ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */ ++ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, ++ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */ ++ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L, ++ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */ ++}; ++ ++ulong ++bcm_strtoul(const char *cp, char **endp, uint base) ++{ ++ ulong result, last_result = 0, value; ++ bool minus; ++ ++ minus = FALSE; ++ ++ while (bcm_isspace(*cp)) ++ cp++; ++ ++ if (cp[0] == '+') ++ cp++; ++ else if (cp[0] == '-') { ++ minus = TRUE; ++ cp++; ++ } ++ ++ if (base == 0) { ++ if (cp[0] == '0') { ++ if ((cp[1] == 'x') || (cp[1] == 'X')) { ++ base = 16; ++ cp = &cp[2]; ++ } else { ++ base = 8; ++ cp = &cp[1]; ++ } ++ } else ++ base = 10; ++ } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) { ++ cp = &cp[2]; ++ } ++ ++ result = 0; ++ ++ while (bcm_isxdigit(*cp) && ++ (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) { ++ result = result*base + value; ++ /* Detected overflow */ ++ if (result < last_result && !minus) ++ return (ulong)-1; ++ last_result = result; ++ cp++; ++ } ++ ++ if (minus) ++ result = (ulong)(-(long)result); ++ ++ if (endp) ++ *endp = DISCARD_QUAL(cp, char); ++ ++ return (result); ++} ++ ++int ++bcm_atoi(const char *s) ++{ ++ return (int)bcm_strtoul(s, NULL, 10); ++} ++ ++/* return pointer to location of substring 'needle' in 'haystack' */ ++char * ++bcmstrstr(const char *haystack, const char *needle) ++{ ++ int len, nlen; ++ int i; ++ ++ if ((haystack == NULL) || (needle == NULL)) ++ return DISCARD_QUAL(haystack, char); ++ ++ nlen = strlen(needle); ++ len = strlen(haystack) - nlen + 1; ++ ++ for (i = 0; i < len; i++) ++ if (memcmp(needle, &haystack[i], nlen) == 0) ++ return DISCARD_QUAL(&haystack[i], char); ++ return (NULL); ++} ++ ++char * ++bcmstrcat(char *dest, const char *src) ++{ ++ char *p; ++ ++ p = dest + strlen(dest); ++ ++ while ((*p++ = *src++) != '\0') ++ ; ++ ++ return (dest); ++} ++ ++char * ++bcmstrncat(char *dest, const char *src, uint size) ++{ ++ char *endp; ++ char *p; ++ ++ p = dest + strlen(dest); ++ endp = p + size; ++ ++ while (p != endp && (*p++ = *src++) != '\0') ++ ; ++ ++ return (dest); ++} ++ ++ ++/**************************************************************************** ++* Function: bcmstrtok ++* ++* Purpose: ++* Tokenizes a string. This function is conceptually similiar to ANSI C strtok(), ++* but allows strToken() to be used by different strings or callers at the same ++* time. Each call modifies '*string' by substituting a NULL character for the ++* first delimiter that is encountered, and updates 'string' to point to the char ++* after the delimiter. Leading delimiters are skipped. ++* ++* Parameters: ++* string (mod) Ptr to string ptr, updated by token. ++* delimiters (in) Set of delimiter characters. ++* tokdelim (out) Character that delimits the returned token. (May ++* be set to NULL if token delimiter is not required). ++* ++* Returns: Pointer to the next token found. NULL when no more tokens are found. ++***************************************************************************** ++*/ ++char * ++bcmstrtok(char **string, const char *delimiters, char *tokdelim) ++{ ++ unsigned char *str; ++ unsigned long map[8]; ++ int count; ++ char *nextoken; ++ ++ if (tokdelim != NULL) { ++ /* Prime the token delimiter */ ++ *tokdelim = '\0'; ++ } ++ ++ /* Clear control map */ ++ for (count = 0; count < 8; count++) { ++ map[count] = 0; ++ } ++ ++ /* Set bits in delimiter table */ ++ do { ++ map[*delimiters >> 5] |= (1 << (*delimiters & 31)); ++ } ++ while (*delimiters++); ++ ++ str = (unsigned char*)*string; ++ ++ /* Find beginning of token (skip over leading delimiters). Note that ++ * there is no token iff this loop sets str to point to the terminal ++ * null (*str == '\0') ++ */ ++ while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) { ++ str++; ++ } ++ ++ nextoken = (char*)str; ++ ++ /* Find the end of the token. If it is not the end of the string, ++ * put a null there. ++ */ ++ for (; *str; str++) { ++ if (map[*str >> 5] & (1 << (*str & 31))) { ++ if (tokdelim != NULL) { ++ *tokdelim = *str; ++ } ++ ++ *str++ = '\0'; ++ break; ++ } ++ } ++ ++ *string = (char*)str; ++ ++ /* Determine if a token has been found. */ ++ if (nextoken == (char *) str) { ++ return NULL; ++ } ++ else { ++ return nextoken; ++ } ++} ++ ++ ++#define xToLower(C) \ ++ ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C) ++ ++ ++/**************************************************************************** ++* Function: bcmstricmp ++* ++* Purpose: Compare to strings case insensitively. ++* ++* Parameters: s1 (in) First string to compare. ++* s2 (in) Second string to compare. ++* ++* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if ++* t1 > t2, when ignoring case sensitivity. ++***************************************************************************** ++*/ ++int ++bcmstricmp(const char *s1, const char *s2) ++{ ++ char dc, sc; ++ ++ while (*s2 && *s1) { ++ dc = xToLower(*s1); ++ sc = xToLower(*s2); ++ if (dc < sc) return -1; ++ if (dc > sc) return 1; ++ s1++; ++ s2++; ++ } ++ ++ if (*s1 && !*s2) return 1; ++ if (!*s1 && *s2) return -1; ++ return 0; ++} ++ ++ ++/**************************************************************************** ++* Function: bcmstrnicmp ++* ++* Purpose: Compare to strings case insensitively, upto a max of 'cnt' ++* characters. ++* ++* Parameters: s1 (in) First string to compare. ++* s2 (in) Second string to compare. ++* cnt (in) Max characters to compare. ++* ++* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if ++* t1 > t2, when ignoring case sensitivity. ++***************************************************************************** ++*/ ++int ++bcmstrnicmp(const char* s1, const char* s2, int cnt) ++{ ++ char dc, sc; ++ ++ while (*s2 && *s1 && cnt) { ++ dc = xToLower(*s1); ++ sc = xToLower(*s2); ++ if (dc < sc) return -1; ++ if (dc > sc) return 1; ++ s1++; ++ s2++; ++ cnt--; ++ } ++ ++ if (!cnt) return 0; ++ if (*s1 && !*s2) return 1; ++ if (!*s1 && *s2) return -1; ++ return 0; ++} ++ ++/* parse a xx:xx:xx:xx:xx:xx format ethernet address */ ++int ++bcm_ether_atoe(const char *p, struct ether_addr *ea) ++{ ++ int i = 0; ++ char *ep; ++ ++ for (;;) { ++ ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16); ++ p = ep; ++ if (!*p++ || i == 6) ++ break; ++ } ++ ++ return (i == 6); ++} ++ ++ ++#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER) ++/* registry routine buffer preparation utility functions: ++ * parameter order is like strncpy, but returns count ++ * of bytes copied. Minimum bytes copied is null char(1)/wchar(2) ++ */ ++ulong ++wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen) ++{ ++ ulong copyct = 1; ++ ushort i; ++ ++ if (abuflen == 0) ++ return 0; ++ ++ /* wbuflen is in bytes */ ++ wbuflen /= sizeof(ushort); ++ ++ for (i = 0; i < wbuflen; ++i) { ++ if (--abuflen == 0) ++ break; ++ *abuf++ = (char) *wbuf++; ++ ++copyct; ++ } ++ *abuf = '\0'; ++ ++ return copyct; ++} ++#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */ ++ ++char * ++bcm_ether_ntoa(const struct ether_addr *ea, char *buf) ++{ ++ static const char hex[] = ++ { ++ '0', '1', '2', '3', '4', '5', '6', '7', ++ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' ++ }; ++ const uint8 *octet = ea->octet; ++ char *p = buf; ++ int i; ++ ++ for (i = 0; i < 6; i++, octet++) { ++ *p++ = hex[(*octet >> 4) & 0xf]; ++ *p++ = hex[*octet & 0xf]; ++ *p++ = ':'; ++ } ++ ++ *(p-1) = '\0'; ++ ++ return (buf); ++} ++ ++char * ++bcm_ip_ntoa(struct ipv4_addr *ia, char *buf) ++{ ++ snprintf(buf, 16, "%d.%d.%d.%d", ++ ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]); ++ return (buf); ++} ++ ++#ifdef BCMDRIVER ++ ++void ++bcm_mdelay(uint ms) ++{ ++ uint i; ++ ++ for (i = 0; i < ms; i++) { ++ OSL_DELAY(1000); ++ } ++} ++ ++ ++ ++ ++ ++#if defined(DHD_DEBUG) ++/* pretty hex print a pkt buffer chain */ ++void ++prpkt(const char *msg, osl_t *osh, void *p0) ++{ ++ void *p; ++ ++ if (msg && (msg[0] != '\0')) ++ AP6211_DEBUG("%s:\n", msg); ++ ++ for (p = p0; p; p = PKTNEXT(osh, p)) ++ prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p)); ++} ++#endif ++ ++/* Takes an Ethernet frame and sets out-of-bound PKTPRIO. ++ * Also updates the inplace vlan tag if requested. ++ * For debugging, it returns an indication of what it did. ++ */ ++uint BCMFASTPATH ++pktsetprio(void *pkt, bool update_vtag) ++{ ++ struct ether_header *eh; ++ struct ethervlan_header *evh; ++ uint8 *pktdata; ++ int priority = 0; ++ int rc = 0; ++ ++ pktdata = (uint8 *)PKTDATA(NULL, pkt); ++ ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); ++ ++ eh = (struct ether_header *) pktdata; ++ ++ if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) { ++ uint16 vlan_tag; ++ int vlan_prio, dscp_prio = 0; ++ ++ evh = (struct ethervlan_header *)eh; ++ ++ vlan_tag = ntoh16(evh->vlan_tag); ++ vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; ++ ++ if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) { ++ uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); ++ uint8 tos_tc = IP_TOS46(ip_body); ++ dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); ++ } ++ ++ /* DSCP priority gets precedence over 802.1P (vlan tag) */ ++ if (dscp_prio != 0) { ++ priority = dscp_prio; ++ rc |= PKTPRIO_VDSCP; ++ } else { ++ priority = vlan_prio; ++ rc |= PKTPRIO_VLAN; ++ } ++ /* ++ * If the DSCP priority is not the same as the VLAN priority, ++ * then overwrite the priority field in the vlan tag, with the ++ * DSCP priority value. This is required for Linux APs because ++ * the VLAN driver on Linux, overwrites the skb->priority field ++ * with the priority value in the vlan tag ++ */ ++ if (update_vtag && (priority != vlan_prio)) { ++ vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); ++ vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; ++ evh->vlan_tag = hton16(vlan_tag); ++ rc |= PKTPRIO_UPD; ++ } ++ } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) { ++ uint8 *ip_body = pktdata + sizeof(struct ether_header); ++ uint8 tos_tc = IP_TOS46(ip_body); ++ priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); ++ rc |= PKTPRIO_DSCP; ++ } ++ ++ ASSERT(priority >= 0 && priority <= MAXPRIO); ++ PKTSETPRIO(pkt, priority); ++ return (rc | priority); ++} ++ ++ ++static char bcm_undeferrstr[32]; ++static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; ++ ++/* Convert the error codes into related error strings */ ++const char * ++bcmerrorstr(int bcmerror) ++{ ++ /* check if someone added a bcmerror code but forgot to add errorstring */ ++ ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1)); ++ ++ if (bcmerror > 0 || bcmerror < BCME_LAST) { ++ snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror); ++ return bcm_undeferrstr; ++ } ++ ++ ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN); ++ ++ return bcmerrorstrtable[-bcmerror]; ++} ++ ++ ++ ++/* iovar table lookup */ ++const bcm_iovar_t* ++bcm_iovar_lookup(const bcm_iovar_t *table, const char *name) ++{ ++ const bcm_iovar_t *vi; ++ const char *lookup_name; ++ ++ /* skip any ':' delimited option prefixes */ ++ lookup_name = strrchr(name, ':'); ++ if (lookup_name != NULL) ++ lookup_name++; ++ else ++ lookup_name = name; ++ ++ ASSERT(table != NULL); ++ ++ for (vi = table; vi->name; vi++) { ++ if (!strcmp(vi->name, lookup_name)) ++ return vi; ++ } ++ /* ran to end of table */ ++ ++ return NULL; /* var name not found */ ++} ++ ++int ++bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) ++{ ++ int bcmerror = 0; ++ ++ /* length check on io buf */ ++ switch (vi->type) { ++ case IOVT_BOOL: ++ case IOVT_INT8: ++ case IOVT_INT16: ++ case IOVT_INT32: ++ case IOVT_UINT8: ++ case IOVT_UINT16: ++ case IOVT_UINT32: ++ /* all integers are int32 sized args at the ioctl interface */ ++ if (len < (int)sizeof(int)) { ++ bcmerror = BCME_BUFTOOSHORT; ++ } ++ break; ++ ++ case IOVT_BUFFER: ++ /* buffer must meet minimum length requirement */ ++ if (len < vi->minlen) { ++ bcmerror = BCME_BUFTOOSHORT; ++ } ++ break; ++ ++ case IOVT_VOID: ++ if (!set) { ++ /* Cannot return nil... */ ++ bcmerror = BCME_UNSUPPORTED; ++ } else if (len) { ++ /* Set is an action w/o parameters */ ++ bcmerror = BCME_BUFTOOLONG; ++ } ++ break; ++ ++ default: ++ /* unknown type for length check in iovar info */ ++ ASSERT(0); ++ bcmerror = BCME_UNSUPPORTED; ++ } ++ ++ return bcmerror; ++} ++ ++#endif /* BCMDRIVER */ ++ ++ ++/******************************************************************************* ++ * crc8 ++ * ++ * Computes a crc8 over the input data using the polynomial: ++ * ++ * x^8 + x^7 +x^6 + x^4 + x^2 + 1 ++ * ++ * The caller provides the initial value (either CRC8_INIT_VALUE ++ * or the previous returned value) to allow for processing of ++ * discontiguous blocks of data. When generating the CRC the ++ * caller is responsible for complementing the final return value ++ * and inserting it into the byte stream. When checking, a final ++ * return value of CRC8_GOOD_VALUE indicates a valid CRC. ++ * ++ * Reference: Dallas Semiconductor Application Note 27 ++ * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", ++ * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., ++ * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt ++ * ++ * **************************************************************************** ++ */ ++ ++static const uint8 crc8_table[256] = { ++ 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, ++ 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, ++ 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, ++ 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, ++ 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, ++ 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, ++ 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, ++ 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, ++ 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, ++ 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, ++ 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, ++ 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, ++ 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, ++ 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, ++ 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, ++ 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, ++ 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, ++ 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, ++ 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, ++ 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, ++ 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, ++ 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, ++ 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, ++ 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, ++ 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, ++ 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, ++ 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, ++ 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, ++ 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, ++ 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, ++ 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, ++ 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F ++}; ++ ++#define CRC_INNER_LOOP(n, c, x) \ ++ (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff] ++ ++uint8 ++hndcrc8( ++ uint8 *pdata, /* pointer to array of data to process */ ++ uint nbytes, /* number of input data bytes to process */ ++ uint8 crc /* either CRC8_INIT_VALUE or previous return value */ ++) ++{ ++ /* hard code the crc loop instead of using CRC_INNER_LOOP macro ++ * to avoid the undefined and unnecessary (uint8 >> 8) operation. ++ */ ++ while (nbytes-- > 0) ++ crc = crc8_table[(crc ^ *pdata++) & 0xff]; ++ ++ return crc; ++} ++ ++/******************************************************************************* ++ * crc16 ++ * ++ * Computes a crc16 over the input data using the polynomial: ++ * ++ * x^16 + x^12 +x^5 + 1 ++ * ++ * The caller provides the initial value (either CRC16_INIT_VALUE ++ * or the previous returned value) to allow for processing of ++ * discontiguous blocks of data. When generating the CRC the ++ * caller is responsible for complementing the final return value ++ * and inserting it into the byte stream. When checking, a final ++ * return value of CRC16_GOOD_VALUE indicates a valid CRC. ++ * ++ * Reference: Dallas Semiconductor Application Note 27 ++ * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", ++ * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., ++ * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt ++ * ++ * **************************************************************************** ++ */ ++ ++static const uint16 crc16_table[256] = { ++ 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, ++ 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, ++ 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, ++ 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, ++ 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, ++ 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, ++ 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, ++ 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, ++ 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, ++ 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, ++ 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, ++ 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, ++ 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, ++ 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, ++ 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, ++ 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, ++ 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, ++ 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, ++ 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, ++ 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, ++ 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, ++ 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, ++ 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, ++ 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, ++ 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, ++ 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, ++ 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, ++ 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, ++ 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, ++ 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, ++ 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, ++ 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 ++}; ++ ++uint16 ++hndcrc16( ++ uint8 *pdata, /* pointer to array of data to process */ ++ uint nbytes, /* number of input data bytes to process */ ++ uint16 crc /* either CRC16_INIT_VALUE or previous return value */ ++) ++{ ++ while (nbytes-- > 0) ++ CRC_INNER_LOOP(16, crc, *pdata++); ++ return crc; ++} ++ ++static const uint32 crc32_table[256] = { ++ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, ++ 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, ++ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, ++ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, ++ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, ++ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, ++ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, ++ 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, ++ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, ++ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, ++ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, ++ 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, ++ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, ++ 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, ++ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, ++ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, ++ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, ++ 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, ++ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, ++ 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, ++ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, ++ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, ++ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, ++ 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, ++ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, ++ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, ++ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, ++ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, ++ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, ++ 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, ++ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, ++ 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, ++ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, ++ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, ++ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, ++ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, ++ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, ++ 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, ++ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, ++ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, ++ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, ++ 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, ++ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, ++ 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, ++ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, ++ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, ++ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, ++ 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, ++ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, ++ 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, ++ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, ++ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, ++ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, ++ 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, ++ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, ++ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, ++ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, ++ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, ++ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, ++ 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, ++ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, ++ 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, ++ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, ++ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D ++}; ++ ++/* ++ * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if ++ * accumulating over multiple pieces. ++ */ ++uint32 ++hndcrc32(uint8 *pdata, uint nbytes, uint32 crc) ++{ ++ uint8 *pend; ++ pend = pdata + nbytes; ++ while (pdata < pend) ++ CRC_INNER_LOOP(32, crc, *pdata++); ++ ++ return crc; ++} ++ ++#ifdef notdef ++#define CLEN 1499 /* CRC Length */ ++#define CBUFSIZ (CLEN+4) ++#define CNBUFS 5 /* # of bufs */ ++ ++void ++testcrc32(void) ++{ ++ uint j, k, l; ++ uint8 *buf; ++ uint len[CNBUFS]; ++ uint32 crcr; ++ uint32 crc32tv[CNBUFS] = ++ {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110}; ++ ++ ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL); ++ ++ /* step through all possible alignments */ ++ for (l = 0; l <= 4; l++) { ++ for (j = 0; j < CNBUFS; j++) { ++ len[j] = CLEN; ++ for (k = 0; k < len[j]; k++) ++ *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff; ++ } ++ ++ for (j = 0; j < CNBUFS; j++) { ++ crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE); ++ ASSERT(crcr == crc32tv[j]); ++ } ++ } ++ ++ MFREE(buf, CBUFSIZ*CNBUFS); ++ return; ++} ++#endif /* notdef */ ++ ++/* ++ * Advance from the current 1-byte tag/1-byte length/variable-length value ++ * triple, to the next, returning a pointer to the next. ++ * If the current or next TLV is invalid (does not fit in given buffer length), ++ * NULL is returned. ++ * *buflen is not modified if the TLV elt parameter is invalid, or is decremented ++ * by the TLV parameter's length if it is valid. ++ */ ++bcm_tlv_t * ++bcm_next_tlv(bcm_tlv_t *elt, int *buflen) ++{ ++ int len; ++ ++ /* validate current elt */ ++ if (!bcm_valid_tlv(elt, *buflen)) ++ return NULL; ++ ++ /* advance to next elt */ ++ len = elt->len; ++ elt = (bcm_tlv_t*)(elt->data + len); ++ *buflen -= (TLV_HDR_LEN + len); ++ ++ /* validate next elt */ ++ if (!bcm_valid_tlv(elt, *buflen)) ++ return NULL; ++ ++ return elt; ++} ++ ++/* ++ * Traverse a string of 1-byte tag/1-byte length/variable-length value ++ * triples, returning a pointer to the substring whose first element ++ * matches tag ++ */ ++bcm_tlv_t * ++bcm_parse_tlvs(void *buf, int buflen, uint key) ++{ ++ bcm_tlv_t *elt; ++ int totlen; ++ ++ elt = (bcm_tlv_t*)buf; ++ totlen = buflen; ++ ++ /* find tagged parameter */ ++ while (totlen >= TLV_HDR_LEN) { ++ int len = elt->len; ++ ++ /* validate remaining totlen */ ++ if ((elt->id == key) && ++ (totlen >= (len + TLV_HDR_LEN))) ++ return (elt); ++ ++ elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); ++ totlen -= (len + TLV_HDR_LEN); ++ } ++ ++ return NULL; ++} ++ ++/* ++ * Traverse a string of 1-byte tag/1-byte length/variable-length value ++ * triples, returning a pointer to the substring whose first element ++ * matches tag. Stop parsing when we see an element whose ID is greater ++ * than the target key. ++ */ ++bcm_tlv_t * ++bcm_parse_ordered_tlvs(void *buf, int buflen, uint key) ++{ ++ bcm_tlv_t *elt; ++ int totlen; ++ ++ elt = (bcm_tlv_t*)buf; ++ totlen = buflen; ++ ++ /* find tagged parameter */ ++ while (totlen >= TLV_HDR_LEN) { ++ uint id = elt->id; ++ int len = elt->len; ++ ++ /* Punt if we start seeing IDs > than target key */ ++ if (id > key) ++ return (NULL); ++ ++ /* validate remaining totlen */ ++ if ((id == key) && ++ (totlen >= (len + TLV_HDR_LEN))) ++ return (elt); ++ ++ elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); ++ totlen -= (len + TLV_HDR_LEN); ++ } ++ return NULL; ++} ++ ++#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \ ++ defined(DHD_DEBUG) ++int ++bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len) ++{ ++ int i; ++ char* p = buf; ++ char hexstr[16]; ++ int slen = 0, nlen = 0; ++ uint32 bit; ++ const char* name; ++ ++ if (len < 2 || !buf) ++ return 0; ++ ++ buf[0] = '\0'; ++ ++ for (i = 0; flags != 0; i++) { ++ bit = bd[i].bit; ++ name = bd[i].name; ++ if (bit == 0 && flags != 0) { ++ /* print any unnamed bits */ ++ snprintf(hexstr, 16, "0x%X", flags); ++ name = hexstr; ++ flags = 0; /* exit loop */ ++ } else if ((flags & bit) == 0) ++ continue; ++ flags &= ~bit; ++ nlen = strlen(name); ++ slen += nlen; ++ /* count btwn flag space */ ++ if (flags != 0) ++ slen += 1; ++ /* need NULL char as well */ ++ if (len <= slen) ++ break; ++ /* copy NULL char but don't count it */ ++ strncpy(p, name, nlen + 1); ++ p += nlen; ++ /* copy btwn flag space and NULL char */ ++ if (flags != 0) ++ p += snprintf(p, 2, " "); ++ } ++ ++ /* indicate the str was too short */ ++ if (flags != 0) { ++ if (len < 2) ++ p -= 2 - len; /* overwrite last char */ ++ p += snprintf(p, 2, ">"); ++ } ++ ++ return (int)(p - buf); ++} ++ ++/* print bytes formatted as hex to a string. return the resulting string length */ ++int ++bcm_format_hex(char *str, const void *bytes, int len) ++{ ++ int i; ++ char *p = str; ++ const uint8 *src = (const uint8*)bytes; ++ ++ for (i = 0; i < len; i++) { ++ p += snprintf(p, 3, "%02X", *src); ++ src++; ++ } ++ return (int)(p - str); ++} ++#endif ++ ++/* pretty hex print a contiguous buffer */ ++void ++prhex(const char *msg, uchar *buf, uint nbytes) ++{ ++ char line[128], *p; ++ int len = sizeof(line); ++ int nchar; ++ uint i; ++ ++ if (msg && (msg[0] != '\0')) ++ AP6211_DEBUG("%s:\n", msg); ++ ++ p = line; ++ for (i = 0; i < nbytes; i++) { ++ if (i % 16 == 0) { ++ nchar = snprintf(p, len, " %04d: ", i); /* line prefix */ ++ p += nchar; ++ len -= nchar; ++ } ++ if (len > 0) { ++ nchar = snprintf(p, len, "%02x ", buf[i]); ++ p += nchar; ++ len -= nchar; ++ } ++ ++ if (i % 16 == 15) { ++ AP6211_DEBUG("%s\n", line); /* flush line */ ++ p = line; ++ len = sizeof(line); ++ } ++ } ++ ++ /* flush last partial line */ ++ if (p != line) ++ AP6211_DUMP("%s\n", line); ++} ++ ++static const char *crypto_algo_names[] = { ++ "NONE", ++ "WEP1", ++ "TKIP", ++ "WEP128", ++ "AES_CCM", ++ "AES_OCB_MSDU", ++ "AES_OCB_MPDU", ++ "NALG" ++ "UNDEF", ++ "UNDEF", ++ "UNDEF", ++#ifdef BCMWAPI_WPI ++ "WAPI", ++#endif /* BCMWAPI_WPI */ ++ "UNDEF" ++}; ++ ++const char * ++bcm_crypto_algo_name(uint algo) ++{ ++ return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR"; ++} ++ ++ ++char * ++bcm_chipname(uint chipid, char *buf, uint len) ++{ ++ const char *fmt; ++ ++ fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; ++ snprintf(buf, len, fmt, chipid); ++ return buf; ++} ++ ++/* Produce a human-readable string for boardrev */ ++char * ++bcm_brev_str(uint32 brev, char *buf) ++{ ++ if (brev < 0x100) ++ snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf); ++ else ++ snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff); ++ ++ return (buf); ++} ++ ++#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */ ++ ++/* dump large strings to console */ ++void ++printbig(char *buf) ++{ ++ uint len, max_len; ++ char c; ++ ++ len = strlen(buf); ++ ++ max_len = BUFSIZE_TODUMP_ATONCE; ++ ++ while (len > max_len) { ++ c = buf[max_len]; ++ buf[max_len] = '\0'; ++ AP6211_DUMP("%s", buf); ++ buf[max_len] = c; ++ ++ buf += max_len; ++ len -= max_len; ++ } ++ /* print the remaining string */ ++ AP6211_DUMP("%s\n", buf); ++ return; ++} ++ ++/* routine to dump fields in a fileddesc structure */ ++uint ++bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array, ++ char *buf, uint32 bufsize) ++{ ++ uint filled_len; ++ int len; ++ struct fielddesc *cur_ptr; ++ ++ filled_len = 0; ++ cur_ptr = fielddesc_array; ++ ++ while (bufsize > 1) { ++ if (cur_ptr->nameandfmt == NULL) ++ break; ++ len = snprintf(buf, bufsize, cur_ptr->nameandfmt, ++ read_rtn(arg0, arg1, cur_ptr->offset)); ++ /* check for snprintf overflow or error */ ++ if (len < 0 || (uint32)len >= bufsize) ++ len = bufsize - 1; ++ buf += len; ++ bufsize -= len; ++ filled_len += len; ++ cur_ptr++; ++ } ++ return filled_len; ++} ++ ++uint ++bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) ++{ ++ uint len; ++ ++ len = strlen(name) + 1; ++ ++ if ((len + datalen) > buflen) ++ return 0; ++ ++ strncpy(buf, name, buflen); ++ ++ /* append data onto the end of the name string */ ++ memcpy(&buf[len], data, datalen); ++ len += datalen; ++ ++ return len; ++} ++ ++/* Quarter dBm units to mW ++ * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153 ++ * Table is offset so the last entry is largest mW value that fits in ++ * a uint16. ++ */ ++ ++#define QDBM_OFFSET 153 /* Offset for first entry */ ++#define QDBM_TABLE_LEN 40 /* Table size */ ++ ++/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET. ++ * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2 ++ */ ++#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */ ++ ++/* Largest mW value that will round down to the last table entry, ++ * QDBM_OFFSET + QDBM_TABLE_LEN-1. ++ * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2. ++ */ ++#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */ ++ ++static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = { ++/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */ ++/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000, ++/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849, ++/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119, ++/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811, ++/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096 ++}; ++ ++uint16 ++bcm_qdbm_to_mw(uint8 qdbm) ++{ ++ uint factor = 1; ++ int idx = qdbm - QDBM_OFFSET; ++ ++ if (idx >= QDBM_TABLE_LEN) { ++ /* clamp to max uint16 mW value */ ++ return 0xFFFF; ++ } ++ ++ /* scale the qdBm index up to the range of the table 0-40 ++ * where an offset of 40 qdBm equals a factor of 10 mW. ++ */ ++ while (idx < 0) { ++ idx += 40; ++ factor *= 10; ++ } ++ ++ /* return the mW value scaled down to the correct factor of 10, ++ * adding in factor/2 to get proper rounding. ++ */ ++ return ((nqdBm_to_mW_map[idx] + factor/2) / factor); ++} ++ ++uint8 ++bcm_mw_to_qdbm(uint16 mw) ++{ ++ uint8 qdbm; ++ int offset; ++ uint mw_uint = mw; ++ uint boundary; ++ ++ /* handle boundary case */ ++ if (mw_uint <= 1) ++ return 0; ++ ++ offset = QDBM_OFFSET; ++ ++ /* move mw into the range of the table */ ++ while (mw_uint < QDBM_TABLE_LOW_BOUND) { ++ mw_uint *= 10; ++ offset -= 40; ++ } ++ ++ for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) { ++ boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] - ++ nqdBm_to_mW_map[qdbm])/2; ++ if (mw_uint < boundary) break; ++ } ++ ++ qdbm += (uint8)offset; ++ ++ return (qdbm); ++} ++ ++ ++uint ++bcm_bitcount(uint8 *bitmap, uint length) ++{ ++ uint bitcount = 0, i; ++ uint8 tmp; ++ for (i = 0; i < length; i++) { ++ tmp = bitmap[i]; ++ while (tmp) { ++ bitcount++; ++ tmp &= (tmp - 1); ++ } ++ } ++ return bitcount; ++} ++ ++#ifdef BCMDRIVER ++ ++/* Initialization of bcmstrbuf structure */ ++void ++bcm_binit(struct bcmstrbuf *b, char *buf, uint size) ++{ ++ b->origsize = b->size = size; ++ b->origbuf = b->buf = buf; ++} ++ ++/* Buffer sprintf wrapper to guard against buffer overflow */ ++int ++bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...) ++{ ++ va_list ap; ++ int r; ++ ++ va_start(ap, fmt); ++ ++ r = vsnprintf(b->buf, b->size, fmt, ap); ++ ++ /* Non Ansi C99 compliant returns -1, ++ * Ansi compliant return r >= b->size, ++ * bcmstdlib returns 0, handle all ++ */ ++ /* r == 0 is also the case when strlen(fmt) is zero. ++ * typically the case when "" is passed as argument. ++ */ ++ if ((r == -1) || (r >= (int)b->size)) { ++ b->size = 0; ++ } else { ++ b->size -= r; ++ b->buf += r; ++ } ++ ++ va_end(ap); ++ ++ return r; ++} ++ ++void ++bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len) ++{ ++ int i; ++ ++ if (msg != NULL && msg[0] != '\0') ++ bcm_bprintf(b, "%s", msg); ++ for (i = 0; i < len; i ++) ++ bcm_bprintf(b, "%02X", buf[i]); ++ if (newline) ++ bcm_bprintf(b, "\n"); ++} ++ ++void ++bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount) ++{ ++ int i; ++ ++ for (i = 0; i < num_bytes; i++) { ++ num[i] += amount; ++ if (num[i] >= amount) ++ break; ++ amount = 1; ++ } ++} ++ ++int ++bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes) ++{ ++ int i; ++ ++ for (i = nbytes - 1; i >= 0; i--) { ++ if (arg1[i] != arg2[i]) ++ return (arg1[i] - arg2[i]); ++ } ++ return 0; ++} ++ ++void ++bcm_print_bytes(const char *name, const uchar *data, int len) ++{ ++ int i; ++ int per_line = 0; ++ ++ AP6211_DEBUG("%s: %d \n", name ? name : "", len); ++ for (i = 0; i < len; i++) { ++ AP6211_DUMP("%02x ", *data++); ++ per_line++; ++ if (per_line == 16) { ++ per_line = 0; ++ AP6211_DUMP("\n"); ++ } ++ } ++ AP6211_DUMP("\n"); ++} ++#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ ++ defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) ++#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1) ++ ++int ++bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len) ++{ ++ uint i, c; ++ char *p = buf; ++ char *endp = buf + SSID_FMT_BUF_LEN; ++ ++ if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN; ++ ++ for (i = 0; i < ssid_len; i++) { ++ c = (uint)ssid[i]; ++ if (c == '\\') { ++ *p++ = '\\'; ++ *p++ = '\\'; ++ } else if (bcm_isprint((uchar)c)) { ++ *p++ = (char)c; ++ } else { ++ p += snprintf(p, (endp - p), "\\x%02X", c); ++ } ++ } ++ *p = '\0'; ++ ASSERT(p < endp); ++ ++ return (int)(p - buf); ++} ++#endif ++ ++#endif /* BCMDRIVER */ ++ ++/* ++ * ProcessVars:Takes a buffer of "=\n" lines read from a file and ending in a NUL. ++ * also accepts nvram files which are already in the format of =\0\=\0 ++ * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs. ++ * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs. ++*/ ++ ++unsigned int ++process_nvram_vars(char *varbuf, unsigned int len) ++{ ++ char *dp; ++ bool findNewline; ++ int column; ++ unsigned int buf_len, n; ++ unsigned int pad = 0; ++ ++ dp = varbuf; ++ ++ findNewline = FALSE; ++ column = 0; ++ ++ for (n = 0; n < len; n++) { ++ if (varbuf[n] == '\r') ++ continue; ++ if (findNewline && varbuf[n] != '\n') ++ continue; ++ findNewline = FALSE; ++ if (varbuf[n] == '#') { ++ findNewline = TRUE; ++ continue; ++ } ++ if (varbuf[n] == '\n') { ++ if (column == 0) ++ continue; ++ *dp++ = 0; ++ column = 0; ++ continue; ++ } ++ *dp++ = varbuf[n]; ++ column++; ++ } ++ buf_len = (unsigned int)(dp - varbuf); ++ if (buf_len % 4) { ++ pad = 4 - buf_len % 4; ++ if (pad && (buf_len + pad <= len)) { ++ buf_len += pad; ++ } ++ } ++ ++ while (dp < varbuf + n) ++ *dp++ = 0; ++ ++ return buf_len; ++} +diff --git a/drivers/net/wireless/ap6211/bcmwifi_channels.c b/drivers/net/wireless/ap6211/bcmwifi_channels.c +new file mode 100755 +index 0000000..6b5b0a3 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/bcmwifi_channels.c +@@ -0,0 +1,1179 @@ ++/* ++ * Misc utility routines used by kernel or app-level. ++ * Contents are wifi-specific, used by any kernel or app-level ++ * software that might want wifi things as it grows. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * $Id: bcmwifi_channels.c 309193 2012-01-19 00:03:57Z $ ++ */ ++ ++#include ++#include ++ ++#ifdef BCMDRIVER ++#include ++#include ++#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) ++#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) ++#else ++#include ++#include ++#include ++#ifndef ASSERT ++#define ASSERT(exp) ++#endif ++#endif /* BCMDRIVER */ ++ ++#ifdef _bcmwifi_c_ ++/* temporary for transitional compatibility */ ++#include ++#else ++#include ++#endif ++ ++#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL)) ++#include /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */ ++#endif ++ ++#ifndef D11AC_IOTYPES ++ ++/* Definitions for legacy Chanspec type */ ++ ++/* Chanspec ASCII representation: ++ * ++ * digit [AB] [N] [UL] ++ * ++ * : channel number of the 10MHz or 20MHz channel, ++ * or control sideband channel of 40MHz channel. ++ * : A for 5GHz, B for 2.4GHz ++ * : N for 10MHz, nothing for 20MHz or 40MHz ++ * (ctl-sideband spec implies 40MHz) ++ * : U for upper, L for lower ++ * ++ * may be omitted on input, and will be assumed to be ++ * 2.4GHz if channel number <= 14. ++ * ++ * Examples: ++ * 8 -> 2.4GHz channel 8, 20MHz ++ * 8b -> 2.4GHz channel 8, 20MHz ++ * 8l -> 2.4GHz channel 8, 40MHz, lower ctl sideband ++ * 8a -> 5GHz channel 8 (low 5 GHz band), 20MHz ++ * 36 -> 5GHz channel 36, 20MHz ++ * 36l -> 5GHz channel 36, 40MHz, lower ctl sideband ++ * 40u -> 5GHz channel 40, 40MHz, upper ctl sideband ++ * 180n -> channel 180, 10MHz ++ */ ++ ++ ++/* given a chanspec and a string buffer, format the chanspec as a ++ * string, and return the original pointer a. ++ * Min buffer length must be CHANSPEC_STR_LEN. ++ * On error return NULL ++ */ ++char * ++wf_chspec_ntoa(chanspec_t chspec, char *buf) ++{ ++ const char *band, *bw, *sb; ++ uint channel; ++ ++ band = ""; ++ bw = ""; ++ sb = ""; ++ channel = CHSPEC_CHANNEL(chspec); ++ /* check for non-default band spec */ ++ if ((CHSPEC_IS2G(chspec) && channel > CH_MAX_2G_CHANNEL) || ++ (CHSPEC_IS5G(chspec) && channel <= CH_MAX_2G_CHANNEL)) ++ band = (CHSPEC_IS2G(chspec)) ? "b" : "a"; ++ if (CHSPEC_IS40(chspec)) { ++ if (CHSPEC_SB_UPPER(chspec)) { ++ sb = "u"; ++ channel += CH_10MHZ_APART; ++ } else { ++ sb = "l"; ++ channel -= CH_10MHZ_APART; ++ } ++ } else if (CHSPEC_IS10(chspec)) { ++ bw = "n"; ++ } ++ ++ /* Outputs a max of 6 chars including '\0' */ ++ snprintf(buf, 6, "%d%s%s%s", channel, band, bw, sb); ++ return (buf); ++} ++ ++/* given a chanspec string, convert to a chanspec. ++ * On error return 0 ++ */ ++chanspec_t ++wf_chspec_aton(const char *a) ++{ ++ char *endp = NULL; ++ uint channel, band, bw, ctl_sb; ++ char c; ++ ++ channel = strtoul(a, &endp, 10); ++ ++ /* check for no digits parsed */ ++ if (endp == a) ++ return 0; ++ ++ if (channel > MAXCHANNEL) ++ return 0; ++ ++ band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); ++ bw = WL_CHANSPEC_BW_20; ++ ctl_sb = WL_CHANSPEC_CTL_SB_NONE; ++ ++ a = endp; ++ ++ c = tolower(a[0]); ++ if (c == '\0') ++ goto done; ++ ++ /* parse the optional ['A' | 'B'] band spec */ ++ if (c == 'a' || c == 'b') { ++ band = (c == 'a') ? WL_CHANSPEC_BAND_5G : WL_CHANSPEC_BAND_2G; ++ a++; ++ c = tolower(a[0]); ++ if (c == '\0') ++ goto done; ++ } ++ ++ /* parse bandwidth 'N' (10MHz) or 40MHz ctl sideband ['L' | 'U'] */ ++ if (c == 'n') { ++ bw = WL_CHANSPEC_BW_10; ++ } else if (c == 'l') { ++ bw = WL_CHANSPEC_BW_40; ++ ctl_sb = WL_CHANSPEC_CTL_SB_LOWER; ++ /* adjust channel to center of 40MHz band */ ++ if (channel <= (MAXCHANNEL - CH_20MHZ_APART)) ++ channel += CH_10MHZ_APART; ++ else ++ return 0; ++ } else if (c == 'u') { ++ bw = WL_CHANSPEC_BW_40; ++ ctl_sb = WL_CHANSPEC_CTL_SB_UPPER; ++ /* adjust channel to center of 40MHz band */ ++ if (channel > CH_20MHZ_APART) ++ channel -= CH_10MHZ_APART; ++ else ++ return 0; ++ } else { ++ return 0; ++ } ++ ++done: ++ return (channel | band | bw | ctl_sb); ++} ++ ++/* ++ * Verify the chanspec is using a legal set of parameters, i.e. that the ++ * chanspec specified a band, bw, ctl_sb and channel and that the ++ * combination could be legal given any set of circumstances. ++ * RETURNS: TRUE is the chanspec is malformed, false if it looks good. ++ */ ++bool ++wf_chspec_malformed(chanspec_t chanspec) ++{ ++ /* must be 2G or 5G band */ ++ if (!CHSPEC_IS5G(chanspec) && !CHSPEC_IS2G(chanspec)) ++ return TRUE; ++ /* must be 20 or 40 bandwidth */ ++ if (!CHSPEC_IS40(chanspec) && !CHSPEC_IS20(chanspec)) ++ return TRUE; ++ ++ /* 20MHZ b/w must have no ctl sb, 40 must have a ctl sb */ ++ if (CHSPEC_IS20(chanspec)) { ++ if (!CHSPEC_SB_NONE(chanspec)) ++ return TRUE; ++ } else { ++ if (!CHSPEC_SB_UPPER(chanspec) && !CHSPEC_SB_LOWER(chanspec)) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/* ++ * This function returns the channel number that control traffic is being sent on, for legacy ++ * channels this is just the channel number, for 40MHZ channels it is the upper or lower 20MHZ ++ * sideband depending on the chanspec selected ++ */ ++uint8 ++wf_chspec_ctlchan(chanspec_t chspec) ++{ ++ uint8 ctl_chan; ++ ++ /* Is there a sideband ? */ ++ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) { ++ return CHSPEC_CHANNEL(chspec); ++ } else { ++ /* we only support 40MHZ with sidebands */ ++ ASSERT(CHSPEC_BW(chspec) == WL_CHANSPEC_BW_40); ++ /* chanspec channel holds the centre frequency, use that and the ++ * side band information to reconstruct the control channel number ++ */ ++ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) { ++ /* control chan is the upper 20 MHZ SB of the 40MHZ channel */ ++ ctl_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec)); ++ } else { ++ ASSERT(CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_LOWER); ++ /* control chan is the lower 20 MHZ SB of the 40MHZ channel */ ++ ctl_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec)); ++ } ++ } ++ ++ return ctl_chan; ++} ++ ++chanspec_t ++wf_chspec_ctlchspec(chanspec_t chspec) ++{ ++ chanspec_t ctl_chspec = 0; ++ uint8 channel; ++ ++ ASSERT(!wf_chspec_malformed(chspec)); ++ ++ /* Is there a sideband ? */ ++ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) { ++ return chspec; ++ } else { ++ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) { ++ channel = UPPER_20_SB(CHSPEC_CHANNEL(chspec)); ++ } else { ++ channel = LOWER_20_SB(CHSPEC_CHANNEL(chspec)); ++ } ++ ctl_chspec = channel | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; ++ ctl_chspec |= CHSPEC_BAND(chspec); ++ } ++ return ctl_chspec; ++} ++ ++#else /* D11AC_IOTYPES */ ++ ++/* Definitions for D11AC capable Chanspec type */ ++ ++/* Chanspec ASCII representation with 802.11ac capability: ++ * [ 'g'] ['/' []['/'<1st80channel>'-'<2nd80channel>]] ++ * ++ * : ++ * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively. ++ * Default value is 2g if channel <= 14, otherwise 5g. ++ * : ++ * channel number of the 5MHz, 10MHz, 20MHz channel, ++ * or primary channel of 40MHz, 80MHz, 160MHz, or 80+80MHz channel. ++ * : ++ * (optional) 5, 10, 20, 40, 80, 160, or 80+80. Default value is 20. ++ * : ++ * (only for 2.4GHz band 40MHz) U for upper sideband primary, L for lower. ++ * ++ * For 2.4GHz band 40MHz channels, the same primary channel may be the ++ * upper sideband for one 40MHz channel, and the lower sideband for an ++ * overlapping 40MHz channel. The U/L disambiguates which 40MHz channel ++ * is being specified. ++ * ++ * For 40MHz in the 5GHz band and all channel bandwidths greater than ++ * 40MHz, the U/L specificaion is not allowed since the channels are ++ * non-overlapping and the primary sub-band is derived from its ++ * position in the wide bandwidth channel. ++ * ++ * <1st80Channel>: ++ * <2nd80Channel>: ++ * Required for 80+80, otherwise not allowed. ++ * Specifies the center channel of the first and second 80MHz band. ++ * ++ * In its simplest form, it is a 20MHz channel number, with the implied band ++ * of 2.4GHz if channel number <= 14, and 5GHz otherwise. ++ * ++ * To allow for backward compatibility with scripts, the old form for ++ * 40MHz channels is also allowed: ++ * ++ * : ++ * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz ++ * : ++ * "U" for upper, "L" for lower (or lower case "u" "l") ++ * ++ * 5 GHz Examples: ++ * Chanspec BW Center Ch Channel Range Primary Ch ++ * 5g8 20MHz 8 - - ++ * 52 20MHz 52 - - ++ * 52/40 40MHz 54 52-56 52 ++ * 56/40 40MHz 54 52-56 56 ++ * 52/80 80MHz 58 52-64 52 ++ * 56/80 80MHz 58 52-64 56 ++ * 60/80 80MHz 58 52-64 60 ++ * 64/80 80MHz 58 52-64 64 ++ * 52/160 160MHz 50 36-64 52 ++ * 36/160 160MGz 50 36-64 36 ++ * 36/80+80/42-106 80+80MHz 42,106 36-48,100-112 36 ++ * ++ * 2 GHz Examples: ++ * Chanspec BW Center Ch Channel Range Primary Ch ++ * 2g8 20MHz 8 - - ++ * 8 20MHz 8 - - ++ * 6 20MHz 6 - - ++ * 6/40l 40MHz 8 6-10 6 ++ * 6l 40MHz 8 6-10 6 ++ * 6/40u 40MHz 4 2-6 6 ++ * 6u 40MHz 4 2-6 6 ++ */ ++ ++/* bandwidth ASCII string */ ++static const char *wf_chspec_bw_str[] = ++{ ++ "5", ++ "10", ++ "20", ++ "40", ++ "80", ++ "160", ++ "80+80", ++ "na" ++}; ++ ++static const uint8 wf_chspec_bw_mhz[] = ++{5, 10, 20, 40, 80, 160, 160}; ++ ++#define WF_NUM_BW \ ++ (sizeof(wf_chspec_bw_mhz)/sizeof(uint8)) ++ ++/* 40MHz channels in 5GHz band */ ++static const uint8 wf_5g_40m_chans[] = ++{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159}; ++#define WF_NUM_5G_40M_CHANS \ ++ (sizeof(wf_5g_40m_chans)/sizeof(uint8)) ++ ++/* 80MHz channels in 5GHz band */ ++static const uint8 wf_5g_80m_chans[] = ++{42, 58, 106, 122, 138, 155}; ++#define WF_NUM_5G_80M_CHANS \ ++ (sizeof(wf_5g_80m_chans)/sizeof(uint8)) ++ ++/* 160MHz channels in 5GHz band */ ++static const uint8 wf_5g_160m_chans[] = ++{50, 114}; ++#define WF_NUM_5G_160M_CHANS \ ++ (sizeof(wf_5g_160m_chans)/sizeof(uint8)) ++ ++ ++/* convert bandwidth from chanspec to MHz */ ++static uint ++bw_chspec_to_mhz(chanspec_t chspec) ++{ ++ uint bw; ++ ++ bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT; ++ return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]); ++} ++ ++/* bw in MHz, return the channel count from the center channel to the ++ * the channel at the edge of the band ++ */ ++static uint8 ++center_chan_to_edge(uint bw) ++{ ++ /* edge channels separated by BW - 10MHz on each side ++ * delta from cf to edge is half of that, ++ * MHz to channel num conversion is 5MHz/channel ++ */ ++ return (uint8)(((bw - 20) / 2) / 5); ++} ++ ++/* return channel number of the low edge of the band ++ * given the center channel and BW ++ */ ++static uint8 ++channel_low_edge(uint center_ch, uint bw) ++{ ++ return (uint8)(center_ch - center_chan_to_edge(bw)); ++} ++ ++/* return side band number given center channel and control channel ++ * return -1 on error ++ */ ++static int ++channel_to_sb(uint center_ch, uint ctl_ch, uint bw) ++{ ++ uint lowest = channel_low_edge(center_ch, bw); ++ uint sb; ++ ++ if ((ctl_ch - lowest) % 4) { ++ /* bad ctl channel, not mult 4 */ ++ return -1; ++ } ++ ++ sb = ((ctl_ch - lowest) / 4); ++ ++ /* sb must be a index to a 20MHz channel in range */ ++ if (sb >= (bw / 20)) { ++ /* ctl_ch must have been too high for the center_ch */ ++ return -1; ++ } ++ ++ return sb; ++} ++ ++/* return control channel given center channel and side band */ ++static uint8 ++channel_to_ctl_chan(uint center_ch, uint bw, uint sb) ++{ ++ return (uint8)(channel_low_edge(center_ch, bw) + sb * 4); ++} ++ ++/* return index of 80MHz channel from channel number ++ * return -1 on error ++ */ ++static int ++channel_80mhz_to_id(uint ch) ++{ ++ uint i; ++ for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) { ++ if (ch == wf_5g_80m_chans[i]) ++ return i; ++ } ++ ++ return -1; ++} ++ ++/* given a chanspec and a string buffer, format the chanspec as a ++ * string, and return the original pointer a. ++ * Min buffer length must be CHANSPEC_STR_LEN. ++ * On error return NULL ++ */ ++char * ++wf_chspec_ntoa(chanspec_t chspec, char *buf) ++{ ++ const char *band; ++ uint ctl_chan; ++ ++ if (wf_chspec_malformed(chspec)) ++ return NULL; ++ ++ band = ""; ++ ++ /* check for non-default band spec */ ++ if ((CHSPEC_IS2G(chspec) && CHSPEC_CHANNEL(chspec) > CH_MAX_2G_CHANNEL) || ++ (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL)) ++ band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g"; ++ ++ /* ctl channel */ ++ ctl_chan = wf_chspec_ctlchan(chspec); ++ ++ /* bandwidth and ctl sideband */ ++ if (CHSPEC_IS20(chspec)) { ++ snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan); ++ } else if (!CHSPEC_IS8080(chspec)) { ++ const char *bw; ++ const char *sb = ""; ++ ++ bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT]; ++ ++#ifdef CHANSPEC_NEW_40MHZ_FORMAT ++ /* ctl sideband string if needed for 2g 40MHz */ ++ if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) { ++ sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; ++ } ++ ++ snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb); ++#else ++ /* ctl sideband string instead of BW for 40MHz */ ++ if (CHSPEC_IS40(chspec)) { ++ sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; ++ snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb); ++ } else { ++ snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw); ++ } ++#endif /* CHANSPEC_NEW_40MHZ_FORMAT */ ++ ++ } else { ++ /* 80+80 */ ++ uint chan1 = (chspec & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT; ++ uint chan2 = (chspec & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT; ++ ++ /* convert to channel number */ ++ chan1 = (chan1 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan1] : 0; ++ chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0; ++ ++ /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */ ++ snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2); ++ } ++ ++ return (buf); ++} ++ ++static int ++read_uint(const char **p, unsigned int *num) ++{ ++ unsigned long val; ++ char *endp = NULL; ++ ++ val = strtoul(*p, &endp, 10); ++ /* if endp is the initial pointer value, then a number was not read */ ++ if (endp == *p) ++ return 0; ++ ++ /* advance the buffer pointer to the end of the integer string */ ++ *p = endp; ++ /* return the parsed integer */ ++ *num = (unsigned int)val; ++ ++ return 1; ++} ++ ++/* given a chanspec string, convert to a chanspec. ++ * On error return 0 ++ */ ++chanspec_t ++wf_chspec_aton(const char *a) ++{ ++ chanspec_t chspec; ++ uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb; ++ uint num, ctl_ch; ++ uint ch1, ch2; ++ char c, sb_ul = '\0'; ++ int i; ++ ++ bw = 20; ++ chspec_sb = 0; ++ chspec_ch = ch1 = ch2 = 0; ++ ++ /* parse channel num or band */ ++ if (!read_uint(&a, &num)) ++ return 0; ++ ++ /* if we are looking at a 'g', then the first number was a band */ ++ c = tolower(a[0]); ++ if (c == 'g') { ++ a ++; /* consume the char */ ++ ++ /* band must be "2" or "5" */ ++ if (num == 2) ++ chspec_band = WL_CHANSPEC_BAND_2G; ++ else if (num == 5) ++ chspec_band = WL_CHANSPEC_BAND_5G; ++ else ++ return 0; ++ ++ /* read the channel number */ ++ if (!read_uint(&a, &ctl_ch)) ++ return 0; ++ ++ c = tolower(a[0]); ++ } ++ else { ++ /* first number is channel, use default for band */ ++ ctl_ch = num; ++ chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? ++ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); ++ } ++ ++ if (c == '\0') { ++ /* default BW of 20MHz */ ++ chspec_bw = WL_CHANSPEC_BW_20; ++ goto done_read; ++ } ++ ++ a ++; /* consume the 'u','l', or '/' */ ++ ++ /* check 'u'/'l' */ ++ if (c == 'u' || c == 'l') { ++ sb_ul = c; ++ chspec_bw = WL_CHANSPEC_BW_40; ++ goto done_read; ++ } ++ ++ /* next letter must be '/' */ ++ if (c != '/') ++ return 0; ++ ++ /* read bandwidth */ ++ if (!read_uint(&a, &bw)) ++ return 0; ++ ++ /* convert to chspec value */ ++ if (bw == 20) { ++ chspec_bw = WL_CHANSPEC_BW_20; ++ } else if (bw == 40) { ++ chspec_bw = WL_CHANSPEC_BW_40; ++ } else if (bw == 80) { ++ chspec_bw = WL_CHANSPEC_BW_80; ++ } else if (bw == 160) { ++ chspec_bw = WL_CHANSPEC_BW_160; ++ } else { ++ return 0; ++ } ++ ++ /* So far we have g/ ++ * Can now be followed by u/l if bw = 40, ++ * or '+80' if bw = 80, to make '80+80' bw. ++ */ ++ ++ c = tolower(a[0]); ++ ++ /* if we have a 2g/40 channel, we should have a l/u spec now */ ++ if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) { ++ if (c == 'u' || c == 'l') { ++ a ++; /* consume the u/l char */ ++ sb_ul = c; ++ goto done_read; ++ } ++ } ++ ++ /* check for 80+80 */ ++ if (c == '+') { ++ /* 80+80 */ ++ static const char *plus80 = "80/"; ++ ++ /* must be looking at '+80/' ++ * check and consume this string. ++ */ ++ chspec_bw = WL_CHANSPEC_BW_8080; ++ ++ a ++; /* consume the char '+' */ ++ ++ /* consume the '80/' string */ ++ for (i = 0; i < 3; i++) { ++ if (*a++ != *plus80++) { ++ return 0; ++ } ++ } ++ ++ /* read primary 80MHz channel */ ++ if (!read_uint(&a, &ch1)) ++ return 0; ++ ++ /* must followed by '-' */ ++ if (a[0] != '-') ++ return 0; ++ a ++; /* consume the char */ ++ ++ /* read secondary 80MHz channel */ ++ if (!read_uint(&a, &ch2)) ++ return 0; ++ } ++ ++done_read: ++ /* skip trailing white space */ ++ while (a[0] == ' ') { ++ a ++; ++ } ++ ++ /* must be end of string */ ++ if (a[0] != '\0') ++ return 0; ++ ++ /* Now have all the chanspec string parts read; ++ * chspec_band, ctl_ch, chspec_bw, sb_ul, ch1, ch2. ++ * chspec_band and chspec_bw are chanspec values. ++ * Need to convert ctl_ch, sb_ul, and ch1,ch2 into ++ * a center channel (or two) and sideband. ++ */ ++ ++ /* if a sb u/l string was given, just use that, ++ * guaranteed to be bw = 40 by sting parse. ++ */ ++ if (sb_ul != '\0') { ++ if (sb_ul == 'l') { ++ chspec_ch = UPPER_20_SB(ctl_ch); ++ chspec_sb = WL_CHANSPEC_CTL_SB_LLL; ++ } else if (sb_ul == 'u') { ++ chspec_ch = LOWER_20_SB(ctl_ch); ++ chspec_sb = WL_CHANSPEC_CTL_SB_LLU; ++ } ++ } ++ /* if the bw is 20, center and sideband are trivial */ ++ else if (chspec_bw == WL_CHANSPEC_BW_20) { ++ chspec_ch = ctl_ch; ++ chspec_sb = 0; ++ } ++ /* if the bw is 40/80/160, not 80+80, a single method ++ * can be used to to find the center and sideband ++ */ ++ else if (chspec_bw != WL_CHANSPEC_BW_8080) { ++ /* figure out ctl sideband based on ctl channel and bandwidth */ ++ const uint8 *center_ch = NULL; ++ int num_ch = 0; ++ int sb = -1; ++ ++ if (chspec_bw == WL_CHANSPEC_BW_40) { ++ center_ch = wf_5g_40m_chans; ++ num_ch = WF_NUM_5G_40M_CHANS; ++ } else if (chspec_bw == WL_CHANSPEC_BW_80) { ++ center_ch = wf_5g_80m_chans; ++ num_ch = WF_NUM_5G_80M_CHANS; ++ } else if (chspec_bw == WL_CHANSPEC_BW_160) { ++ center_ch = wf_5g_160m_chans; ++ num_ch = WF_NUM_5G_160M_CHANS; ++ } else { ++ return 0; ++ } ++ ++ for (i = 0; i < num_ch; i ++) { ++ sb = channel_to_sb(center_ch[i], ctl_ch, bw); ++ if (sb >= 0) { ++ chspec_ch = center_ch[i]; ++ chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; ++ break; ++ } ++ } ++ ++ /* check for no matching sb/center */ ++ if (sb < 0) { ++ return 0; ++ } ++ } ++ /* Otherwise, bw is 80+80. Figure out channel pair and sb */ ++ else { ++ int ch1_id = 0, ch2_id = 0; ++ int sb; ++ ++ ch1_id = channel_80mhz_to_id(ch1); ++ ch2_id = channel_80mhz_to_id(ch2); ++ ++ /* validate channels */ ++ if (ch1 >= ch2 || ch1_id < 0 || ch2_id < 0) ++ return 0; ++ ++ /* combined channel in chspec */ ++ chspec_ch = (((uint16)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) | ++ ((uint16)ch2_id << WL_CHANSPEC_CHAN2_SHIFT)); ++ ++ /* figure out ctl sideband */ ++ ++ /* does the primary channel fit with the 1st 80MHz channel ? */ ++ sb = channel_to_sb(ch1, ctl_ch, bw); ++ if (sb < 0) { ++ /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ ++ sb = channel_to_sb(ch2, ctl_ch, bw); ++ if (sb < 0) { ++ /* no match for ctl_ch to either 80MHz center channel */ ++ return 0; ++ } ++ /* sb index is 0-3 for the low 80MHz channel, and 4-7 for ++ * the high 80MHz channel. Add 4 to to shift to high set. ++ */ ++ sb += 4; ++ } ++ ++ chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; ++ } ++ ++ chspec = (chspec_ch | chspec_band | chspec_bw | chspec_sb); ++ ++ if (wf_chspec_malformed(chspec)) ++ return 0; ++ ++ return chspec; ++} ++ ++/* ++ * Verify the chanspec is using a legal set of parameters, i.e. that the ++ * chanspec specified a band, bw, ctl_sb and channel and that the ++ * combination could be legal given any set of circumstances. ++ * RETURNS: TRUE is the chanspec is malformed, false if it looks good. ++ */ ++bool ++wf_chspec_malformed(chanspec_t chanspec) ++{ ++ uint chspec_bw = CHSPEC_BW(chanspec); ++ uint chspec_ch = CHSPEC_CHANNEL(chanspec); ++ ++ /* must be 2G or 5G band */ ++ if (CHSPEC_IS2G(chanspec)) { ++ /* must be valid bandwidth */ ++ if (chspec_bw != WL_CHANSPEC_BW_20 && ++ chspec_bw != WL_CHANSPEC_BW_40) { ++ return TRUE; ++ } ++ } else if (CHSPEC_IS5G(chanspec)) { ++ if (chspec_bw == WL_CHANSPEC_BW_8080) { ++ uint ch1_id, ch2_id; ++ ++ /* channel number in 80+80 must be in range */ ++ ch1_id = CHSPEC_CHAN1(chanspec); ++ ch2_id = CHSPEC_CHAN2(chanspec); ++ if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS) ++ return TRUE; ++ ++ /* ch2 must be above ch1 for the chanspec */ ++ if (ch2_id <= ch1_id) ++ return TRUE; ++ } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 || ++ chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) { ++ ++ if (chspec_ch > MAXCHANNEL) { ++ return TRUE; ++ } ++ } else { ++ /* invalid bandwidth */ ++ return TRUE; ++ } ++ } else { ++ /* must be 2G or 5G band */ ++ return TRUE; ++ } ++ ++ /* side band needs to be consistent with bandwidth */ ++ if (chspec_bw == WL_CHANSPEC_BW_20) { ++ if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL) ++ return TRUE; ++ } else if (chspec_bw == WL_CHANSPEC_BW_40) { ++ if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LLU) ++ return TRUE; ++ } else if (chspec_bw == WL_CHANSPEC_BW_80) { ++ if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/* ++ * Verify the chanspec specifies a valid channel according to 802.11. ++ * RETURNS: TRUE if the chanspec is a valid 802.11 channel ++ */ ++bool ++wf_chspec_valid(chanspec_t chanspec) ++{ ++ uint chspec_bw = CHSPEC_BW(chanspec); ++ uint chspec_ch = CHSPEC_CHANNEL(chanspec); ++ ++ if (wf_chspec_malformed(chanspec)) ++ return FALSE; ++ ++ if (CHSPEC_IS2G(chanspec)) { ++ /* must be valid bandwidth and channel range */ ++ if (chspec_bw == WL_CHANSPEC_BW_20) { ++ if (chspec_ch >= 1 && chspec_ch <= 14) ++ return TRUE; ++ } else if (chspec_bw == WL_CHANSPEC_BW_40) { ++ if (chspec_ch >= 3 && chspec_ch <= 11) ++ return TRUE; ++ } ++ } else if (CHSPEC_IS5G(chanspec)) { ++ if (chspec_bw == WL_CHANSPEC_BW_8080) { ++ uint16 ch1, ch2; ++ ++ ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)]; ++ ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)]; ++ ++ /* the two channels must be separated by more than 80MHz by VHT req, ++ * and ch2 above ch1 for the chanspec ++ */ ++ if (ch2 > ch1 + CH_80MHZ_APART) ++ return TRUE; ++ } else { ++ const uint8 *center_ch; ++ uint num_ch, i; ++ ++ if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40) { ++ center_ch = wf_5g_40m_chans; ++ num_ch = WF_NUM_5G_40M_CHANS; ++ } else if (chspec_bw == WL_CHANSPEC_BW_80) { ++ center_ch = wf_5g_80m_chans; ++ num_ch = WF_NUM_5G_80M_CHANS; ++ } else if (chspec_bw == WL_CHANSPEC_BW_160) { ++ center_ch = wf_5g_160m_chans; ++ num_ch = WF_NUM_5G_160M_CHANS; ++ } else { ++ /* invalid bandwidth */ ++ return FALSE; ++ } ++ ++ /* check for a valid center channel */ ++ if (chspec_bw == WL_CHANSPEC_BW_20) { ++ /* We don't have an array of legal 20MHz 5G channels, but they are ++ * each side of the legal 40MHz channels. Check the chanspec ++ * channel against either side of the 40MHz channels. ++ */ ++ for (i = 0; i < num_ch; i ++) { ++ if (chspec_ch == (uint)LOWER_20_SB(center_ch[i]) || ++ chspec_ch == (uint)UPPER_20_SB(center_ch[i])) ++ break; /* match found */ ++ } ++ ++ if (i == num_ch) { ++ /* check for legacy JP channels on failure */ ++ if (chspec_ch == 34 || chspec_ch == 38 || ++ chspec_ch == 42 || chspec_ch == 46) ++ i = 0; ++ } ++ } else { ++ /* check the chanspec channel to each legal channel */ ++ for (i = 0; i < num_ch; i ++) { ++ if (chspec_ch == center_ch[i]) ++ break; /* match found */ ++ } ++ } ++ ++ if (i < num_ch) { ++ /* match found */ ++ return TRUE; ++ } ++ } ++ } ++ ++ return FALSE; ++} ++ ++/* ++ * This function returns the channel number that control traffic is being sent on, for 20MHz ++ * channels this is just the channel number, for 40MHZ, 80MHz, 160MHz channels it is the 20MHZ ++ * sideband depending on the chanspec selected ++ */ ++uint8 ++wf_chspec_ctlchan(chanspec_t chspec) ++{ ++ uint center_chan; ++ uint bw_mhz; ++ uint sb; ++ ++ ASSERT(!wf_chspec_malformed(chspec)); ++ ++ /* Is there a sideband ? */ ++ if (CHSPEC_IS20(chspec)) { ++ return CHSPEC_CHANNEL(chspec); ++ } else { ++ sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT; ++ ++ if (CHSPEC_IS8080(chspec)) { ++ bw_mhz = 80; ++ ++ if (sb < 4) { ++ center_chan = CHSPEC_CHAN1(chspec); ++ } ++ else { ++ center_chan = CHSPEC_CHAN2(chspec); ++ sb -= 4; ++ } ++ ++ /* convert from channel index to channel number */ ++ center_chan = wf_5g_80m_chans[center_chan]; ++ } ++ else { ++ bw_mhz = bw_chspec_to_mhz(chspec); ++ center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT; ++ } ++ ++ return (channel_to_ctl_chan(center_chan, bw_mhz, sb)); ++ } ++} ++ ++/* ++ * This function returns the chanspec of the control channel of a given chanspec ++ */ ++chanspec_t ++wf_chspec_ctlchspec(chanspec_t chspec) ++{ ++ chanspec_t ctl_chspec = chspec; ++ uint8 ctl_chan; ++ ++ ASSERT(!wf_chspec_malformed(chspec)); ++ ++ /* Is there a sideband ? */ ++ if (!CHSPEC_IS20(chspec)) { ++ ctl_chan = wf_chspec_ctlchan(chspec); ++ ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20; ++ ctl_chspec |= CHSPEC_BAND(chspec); ++ } ++ return ctl_chspec; ++} ++ ++/* return chanspec given control channel and bandwidth ++ * return 0 on error ++ */ ++uint16 ++wf_channel2chspec(uint ctl_ch, uint bw) ++{ ++ uint16 chspec; ++ const uint8 *center_ch = NULL; ++ int num_ch = 0; ++ int sb = -1; ++ int i = 0; ++ ++ chspec = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); ++ ++ chspec |= bw; ++ ++ if (bw == WL_CHANSPEC_BW_40) { ++ center_ch = wf_5g_40m_chans; ++ num_ch = WF_NUM_5G_40M_CHANS; ++ bw = 40; ++ } else if (bw == WL_CHANSPEC_BW_80) { ++ center_ch = wf_5g_80m_chans; ++ num_ch = WF_NUM_5G_80M_CHANS; ++ bw = 80; ++ } else if (bw == WL_CHANSPEC_BW_160) { ++ center_ch = wf_5g_160m_chans; ++ num_ch = WF_NUM_5G_160M_CHANS; ++ bw = 160; ++ } else if (bw == WL_CHANSPEC_BW_20) { ++ chspec |= ctl_ch; ++ return chspec; ++ } else { ++ return 0; ++ } ++ ++ for (i = 0; i < num_ch; i ++) { ++ sb = channel_to_sb(center_ch[i], ctl_ch, bw); ++ if (sb >= 0) { ++ chspec |= center_ch[i]; ++ chspec |= (sb << WL_CHANSPEC_CTL_SB_SHIFT); ++ break; ++ } ++ } ++ ++ /* check for no matching sb/center */ ++ if (sb < 0) { ++ return 0; ++ } ++ ++ return chspec; ++} ++#endif /* D11AC_IOTYPES */ ++ ++/* ++ * This function returns the chanspec for the primary 40MHz of an 80MHz channel. ++ * The control sideband specifies the same 20MHz channel that the 80MHz channel is using ++ * as the primary 20MHz channel. ++ */ ++extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec) ++{ ++ chanspec_t chspec40 = chspec; ++ uint center_chan; ++ uint sb; ++ ++ ASSERT(!wf_chspec_malformed(chspec)); ++ ++ if (CHSPEC_IS80(chspec)) { ++ center_chan = CHSPEC_CHANNEL(chspec); ++ sb = CHSPEC_CTL_SB(chspec); ++ ++ if (sb == WL_CHANSPEC_CTL_SB_UL) { ++ /* Primary 40MHz is on upper side */ ++ sb = WL_CHANSPEC_CTL_SB_L; ++ center_chan += CH_20MHZ_APART; ++ } else if (sb == WL_CHANSPEC_CTL_SB_UU) { ++ /* Primary 40MHz is on upper side */ ++ sb = WL_CHANSPEC_CTL_SB_U; ++ center_chan += CH_20MHZ_APART; ++ } else { ++ /* Primary 40MHz is on lower side */ ++ /* sideband bits are the same for LL/LU and L/U */ ++ center_chan -= CH_20MHZ_APART; ++ } ++ ++ /* Create primary 40MHz chanspec */ ++ chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 | ++ sb | center_chan); ++ } ++ ++ return chspec40; ++} ++ ++/* ++ * Return the channel number for a given frequency and base frequency. ++ * The returned channel number is relative to the given base frequency. ++ * If the given base frequency is zero, a base frequency of 5 GHz is assumed for ++ * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. ++ * ++ * Frequency is specified in MHz. ++ * The base frequency is specified as (start_factor * 500 kHz). ++ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for ++ * 2.4 GHz and 5 GHz bands. ++ * ++ * The returned channel will be in the range [1, 14] in the 2.4 GHz band ++ * and [0, 200] otherwise. ++ * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the ++ * frequency is not a 2.4 GHz channel, or if the frequency is not and even ++ * multiple of 5 MHz from the base frequency to the base plus 1 GHz. ++ * ++ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 ++ */ ++int ++wf_mhz2channel(uint freq, uint start_factor) ++{ ++ int ch = -1; ++ uint base; ++ int offset; ++ ++ /* take the default channel start frequency */ ++ if (start_factor == 0) { ++ if (freq >= 2400 && freq <= 2500) ++ start_factor = WF_CHAN_FACTOR_2_4_G; ++ else if (freq >= 5000 && freq <= 6000) ++ start_factor = WF_CHAN_FACTOR_5_G; ++ } ++ ++ if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G) ++ return 14; ++ ++ base = start_factor / 2; ++ ++ /* check that the frequency is in 1GHz range of the base */ ++ if ((freq < base) || (freq > base + 1000)) ++ return -1; ++ ++ offset = freq - base; ++ ch = offset / 5; ++ ++ /* check that frequency is a 5MHz multiple from the base */ ++ if (offset != (ch * 5)) ++ return -1; ++ ++ /* restricted channel range check for 2.4G */ ++ if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13)) ++ return -1; ++ ++ return ch; ++} ++ ++/* ++ * Return the center frequency in MHz of the given channel and base frequency. ++ * The channel number is interpreted relative to the given base frequency. ++ * ++ * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. ++ * The base frequency is specified as (start_factor * 500 kHz). ++ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_4_G, and WF_CHAN_FACTOR_5_G ++ * are defined for 2.4 GHz, 4 GHz, and 5 GHz bands. ++ * The channel range of [1, 14] is only checked for a start_factor of ++ * WF_CHAN_FACTOR_2_4_G (4814 = 2407 * 2). ++ * Odd start_factors produce channels on .5 MHz boundaries, in which case ++ * the answer is rounded down to an integral MHz. ++ * -1 is returned for an out of range channel. ++ * ++ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 ++ */ ++int ++wf_channel2mhz(uint ch, uint start_factor) ++{ ++ int freq; ++ ++ if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) || ++ (ch > 200)) ++ freq = -1; ++ else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14)) ++ freq = 2484; ++ else ++ freq = ch * 5 + start_factor / 2; ++ ++ return freq; ++} +diff --git a/drivers/net/wireless/ap6211/dhd.h b/drivers/net/wireless/ap6211/dhd.h +new file mode 100755 +index 0000000..006a41c +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd.h +@@ -0,0 +1,888 @@ ++/* ++ * Header file describing the internal (inter-module) DHD interfaces. ++ * ++ * Provides type definitions and function prototypes used to link the ++ * DHD OS, bus, and protocol modules. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd.h 373887 2012-12-10 21:58:02Z $ ++ */ ++ ++/**************** ++ * Common types * ++ */ ++ ++#ifndef _dhd_h_ ++#define _dhd_h_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) ++#include ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ ++/* The kernel threading is sdio-specific */ ++struct task_struct; ++struct sched_param; ++int setScheduler(struct task_struct *p, int policy, struct sched_param *param); ++ ++#define ALL_INTERFACES 0xff ++ ++#include ++#include ++ ++ ++/* Forward decls */ ++struct dhd_bus; ++struct dhd_prot; ++struct dhd_info; ++ ++/* The level of bus communication with the dongle */ ++enum dhd_bus_state { ++ DHD_BUS_DOWN, /* Not ready for frame transfers */ ++ DHD_BUS_LOAD, /* Download access only (CPU reset) */ ++ DHD_BUS_DATA /* Ready for frame transfers */ ++}; ++ ++enum dhd_op_flags { ++/* Firmware requested operation mode */ ++ DHD_FLAG_STA_MODE = BIT(0), /* STA only */ ++ DHD_FLAG_HOSTAP_MODE = BIT(1), /* SOFTAP only */ ++ DHD_FLAG_P2P_MODE = BIT(2), /* P2P Only */ ++ /* STA + P2P */ ++ DHD_FLAG_CONCURR_SINGLE_CHAN_MODE = (DHD_FLAG_STA_MODE | DHD_FLAG_P2P_MODE), ++ DHD_FLAG_CONCURR_MULTI_CHAN_MODE = BIT(4), /* STA + P2P */ ++ /* Current P2P mode for P2P connection */ ++ DHD_FLAG_P2P_GC_MODE = BIT(5), ++ DHD_FLAG_P2P_GO_MODE = BIT(6), ++ DHD_FLAG_MBSS_MODE = BIT(7) /* MBSS in future */ ++}; ++ ++#define MANUFACTRING_FW "WLTEST" ++ ++/* max sequential rxcntl timeouts to set HANG event */ ++#ifndef MAX_CNTL_TIMEOUT ++#define MAX_CNTL_TIMEOUT 2 ++#endif ++ ++#define DHD_SCAN_ASSOC_ACTIVE_TIME 40 /* ms: Embedded default Active setting from DHD */ ++#define DHD_SCAN_UNASSOC_ACTIVE_TIME 80 /* ms: Embedded def. Unassoc Active setting from DHD */ ++#define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD */ ++ ++#ifndef POWERUP_MAX_RETRY ++#define POWERUP_MAX_RETRY 3 /* how many times we retry to power up the chip */ ++#endif ++#ifndef POWERUP_WAIT_MS ++#define POWERUP_WAIT_MS 2000 /* ms: time out in waiting wifi to come up */ ++#endif ++ ++enum dhd_bus_wake_state { ++ WAKE_LOCK_OFF, ++ WAKE_LOCK_PRIV, ++ WAKE_LOCK_DPC, ++ WAKE_LOCK_IOCTL, ++ WAKE_LOCK_DOWNLOAD, ++ WAKE_LOCK_TMOUT, ++ WAKE_LOCK_WATCHDOG, ++ WAKE_LOCK_LINK_DOWN_TMOUT, ++ WAKE_LOCK_PNO_FIND_TMOUT, ++ WAKE_LOCK_SOFTAP_SET, ++ WAKE_LOCK_SOFTAP_STOP, ++ WAKE_LOCK_SOFTAP_START, ++ WAKE_LOCK_SOFTAP_THREAD, ++ WAKE_LOCK_MAX ++}; ++ ++enum dhd_prealloc_index { ++ DHD_PREALLOC_PROT = 0, ++ DHD_PREALLOC_RXBUF, ++ DHD_PREALLOC_DATABUF, ++#if defined(STATIC_WL_PRIV_STRUCT) ++ DHD_PREALLOC_OSL_BUF, ++ DHD_PREALLOC_WIPHY_ESCAN0 = 5, ++#else ++ DHD_PREALLOC_OSL_BUF ++#endif /* STATIC_WL_PRIV_STRUCT */ ++}; ++ ++typedef enum { ++ DHD_IF_NONE = 0, ++ DHD_IF_ADD, ++ DHD_IF_DEL, ++ DHD_IF_CHANGE, ++ DHD_IF_DELETING ++} dhd_if_state_t; ++ ++ ++#if defined(CONFIG_DHD_USE_STATIC_BUF) ++ ++uint8* dhd_os_prealloc(void *osh, int section, uint size); ++void dhd_os_prefree(void *osh, void *addr, uint size); ++#define DHD_OS_PREALLOC(osh, section, size) dhd_os_prealloc(osh, section, size) ++#define DHD_OS_PREFREE(osh, addr, size) dhd_os_prefree(osh, addr, size) ++ ++#else ++ ++#define DHD_OS_PREALLOC(osh, section, size) MALLOC(osh, size) ++#define DHD_OS_PREFREE(osh, addr, size) MFREE(osh, addr, size) ++ ++#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */ ++ ++/* Packet alignment for most efficient SDIO (can change based on platform) */ ++#ifndef DHD_SDALIGN ++#define DHD_SDALIGN 32 ++#endif ++ ++/* host reordering packts logic */ ++/* followed the structure to hold the reorder buffers (void **p) */ ++typedef struct reorder_info { ++ void **p; ++ uint8 flow_id; ++ uint8 cur_idx; ++ uint8 exp_idx; ++ uint8 max_idx; ++ uint8 pend_pkts; ++} reorder_info_t; ++ ++/* Common structure for module and instance linkage */ ++typedef struct dhd_pub { ++ /* Linkage ponters */ ++ osl_t *osh; /* OSL handle */ ++ struct dhd_bus *bus; /* Bus module handle */ ++ struct dhd_prot *prot; /* Protocol module handle */ ++ struct dhd_info *info; /* Info module handle */ ++ ++ /* Internal dhd items */ ++ bool up; /* Driver up/down (to OS) */ ++ bool txoff; /* Transmit flow-controlled */ ++ bool dongle_reset; /* TRUE = DEVRESET put dongle into reset */ ++ enum dhd_bus_state busstate; ++ uint hdrlen; /* Total DHD header length (proto + bus) */ ++ uint maxctl; /* Max size rxctl request from proto to bus */ ++ uint rxsz; /* Rx buffer size bus module should use */ ++ uint8 wme_dp; /* wme discard priority */ ++ ++ /* Dongle media info */ ++ bool iswl; /* Dongle-resident driver is wl */ ++ ulong drv_version; /* Version of dongle-resident driver */ ++ struct ether_addr mac; /* MAC address obtained from dongle */ ++ dngl_stats_t dstats; /* Stats for dongle-based data */ ++ ++ /* Additional stats for the bus level */ ++ ulong tx_packets; /* Data packets sent to dongle */ ++ ulong tx_multicast; /* Multicast data packets sent to dongle */ ++ ulong tx_errors; /* Errors in sending data to dongle */ ++ ulong tx_ctlpkts; /* Control packets sent to dongle */ ++ ulong tx_ctlerrs; /* Errors sending control frames to dongle */ ++ ulong rx_packets; /* Packets sent up the network interface */ ++ ulong rx_multicast; /* Multicast packets sent up the network interface */ ++ ulong rx_errors; /* Errors processing rx data packets */ ++ ulong rx_ctlpkts; /* Control frames processed from dongle */ ++ ulong rx_ctlerrs; /* Errors in processing rx control frames */ ++ ulong rx_dropped; /* Packets dropped locally (no memory) */ ++ ulong rx_flushed; /* Packets flushed due to unscheduled sendup thread */ ++ ulong wd_dpc_sched; /* Number of times dhd dpc scheduled by watchdog timer */ ++ ++ ulong rx_readahead_cnt; /* Number of packets where header read-ahead was used. */ ++ ulong tx_realloc; /* Number of tx packets we had to realloc for headroom */ ++ ulong fc_packets; /* Number of flow control pkts recvd */ ++ ++ /* Last error return */ ++ int bcmerror; ++ uint tickcnt; ++ ++ /* Last error from dongle */ ++ int dongle_error; ++ ++ uint8 country_code[WLC_CNTRY_BUF_SZ]; ++ ++ /* Suspend disable flag and "in suspend" flag */ ++ int suspend_disable_flag; /* "1" to disable all extra powersaving during suspend */ ++ int in_suspend; /* flag set to 1 when early suspend called */ ++#ifdef PNO_SUPPORT ++ int pno_enable; /* pno status : "1" is pno enable */ ++ int pno_suspend; /* pno suspend status : "1" is pno suspended */ ++#endif /* PNO_SUPPORT */ ++ /* DTIM skip value, default 0(or 1) means wake each DTIM ++ * 3 means skip 2 DTIMs and wake up 3rd DTIM(9th beacon when AP DTIM is 3) ++ */ ++ int suspend_bcn_li_dtim; /* bcn_li_dtim value in suspend mode */ ++#ifdef PKT_FILTER_SUPPORT ++ int early_suspended; /* Early suspend status */ ++ int dhcp_in_progress; /* DHCP period */ ++#endif ++ ++ /* Pkt filter defination */ ++ char * pktfilter[100]; ++ int pktfilter_count; ++ ++ wl_country_t dhd_cspec; /* Current Locale info */ ++ char eventmask[WL_EVENTING_MASK_LEN]; ++ int op_mode; /* STA, HostAPD, WFD, SoftAP */ ++ ++/* Set this to 1 to use a seperate interface (p2p0) for p2p operations. ++ * For ICS MR1 releases it should be disable to be compatable with ICS MR1 Framework ++ * see target dhd-cdc-sdmmc-panda-cfg80211-icsmr1-gpl-debug in Makefile ++ */ ++/* #define WL_ENABLE_P2P_IF 1 */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ struct mutex wl_start_stop_lock; /* lock/unlock for Android start/stop */ ++ struct mutex wl_softap_lock; /* lock/unlock for any SoftAP/STA settings */ ++#endif ++ ++#ifdef WLBTAMP ++ uint16 maxdatablks; ++#endif /* WLBTAMP */ ++#ifdef PROP_TXSTATUS ++ int wlfc_enabled; ++ void* wlfc_state; ++#endif ++ bool dongle_isolation; ++ bool dongle_trap_occured; /* flag for sending HANG event to upper layer */ ++ int hang_was_sent; ++ int rxcnt_timeout; /* counter rxcnt timeout to send HANG */ ++ int txcnt_timeout; /* counter txcnt timeout to send HANG */ ++#ifdef WLMEDIA_HTSF ++ uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */ ++#endif ++ struct reorder_info *reorder_bufs[WLHOST_REORDERDATA_MAXFLOWS]; ++#if defined(ARP_OFFLOAD_SUPPORT) ++ uint32 arp_version; ++#endif ++} dhd_pub_t; ++ ++ ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) ++ ++ #define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); ++ #define _DHD_PM_RESUME_WAIT(a, b) do {\ ++ int retry = 0; \ ++ SMP_RD_BARRIER_DEPENDS(); \ ++ while (dhd_mmc_suspend && retry++ != b) { \ ++ SMP_RD_BARRIER_DEPENDS(); \ ++ wait_event_interruptible_timeout(a, !dhd_mmc_suspend, 1); \ ++ } \ ++ } while (0) ++ #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 200) ++ #define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0) ++ #define DHD_PM_RESUME_RETURN_ERROR(a) do { if (dhd_mmc_suspend) return a; } while (0) ++ #define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0) ++ ++ #define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); ++ #define SPINWAIT_SLEEP(a, exp, us) do { \ ++ uint countdown = (us) + 9999; \ ++ while ((exp) && (countdown >= 10000)) { \ ++ wait_event_interruptible_timeout(a, FALSE, 1); \ ++ countdown -= 10000; \ ++ } \ ++ } while (0) ++ ++ #else ++ ++ #define DHD_PM_RESUME_WAIT_INIT(a) ++ #define DHD_PM_RESUME_WAIT(a) ++ #define DHD_PM_RESUME_WAIT_FOREVER(a) ++ #define DHD_PM_RESUME_RETURN_ERROR(a) ++ #define DHD_PM_RESUME_RETURN ++ ++ #define DHD_SPINWAIT_SLEEP_INIT(a) ++ #define SPINWAIT_SLEEP(a, exp, us) do { \ ++ uint countdown = (us) + 9; \ ++ while ((exp) && (countdown >= 10)) { \ ++ OSL_DELAY(10); \ ++ countdown -= 10; \ ++ } \ ++ } while (0) ++ ++ #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ ++#ifndef DHDTHREAD ++#undef SPINWAIT_SLEEP ++#define SPINWAIT_SLEEP(a, exp, us) SPINWAIT(exp, us) ++#endif /* DHDTHREAD */ ++#define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */ ++ ++unsigned long dhd_os_spin_lock(dhd_pub_t *pub); ++void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags); ++ ++/* Wakelock Functions */ ++extern int dhd_os_wake_lock(dhd_pub_t *pub); ++extern int dhd_os_wake_unlock(dhd_pub_t *pub); ++extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub); ++extern int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val); ++extern int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val); ++extern int dhd_os_wd_wake_lock(dhd_pub_t *pub); ++extern int dhd_os_wd_wake_unlock(dhd_pub_t *pub); ++ ++inline static void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ mutex_init(&dhdp->wl_softap_lock); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++} ++ ++inline static void MUTEX_LOCK_SOFTAP_SET(dhd_pub_t * dhdp) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ mutex_lock(&dhdp->wl_softap_lock); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++} ++ ++inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ mutex_unlock(&dhdp->wl_softap_lock); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++} ++ ++#define DHD_OS_WAKE_LOCK(pub) dhd_os_wake_lock(pub) ++#define DHD_OS_WAKE_UNLOCK(pub) dhd_os_wake_unlock(pub) ++#define DHD_OS_WD_WAKE_LOCK(pub) dhd_os_wd_wake_lock(pub) ++#define DHD_OS_WD_WAKE_UNLOCK(pub) dhd_os_wd_wake_unlock(pub) ++#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub) ++#define DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(pub, val) \ ++ dhd_os_wake_lock_rx_timeout_enable(pub, val) ++#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(pub, val) \ ++ dhd_os_wake_lock_ctrl_timeout_enable(pub, val) ++#define DHD_PACKET_TIMEOUT_MS 1000 ++#define DHD_EVENT_TIMEOUT_MS 1500 ++ ++/* interface operations (register, remove) should be atomic, use this lock to prevent race ++ * condition among wifi on/off and interface operation functions ++ */ ++void dhd_net_if_lock(struct net_device *dev); ++void dhd_net_if_unlock(struct net_device *dev); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++extern struct mutex _dhd_sdio_mutex_lock_; ++#endif ++ ++typedef struct dhd_if_event { ++ uint8 ifidx; ++ uint8 action; ++ uint8 flags; ++ uint8 bssidx; ++ uint8 is_AP; ++} dhd_if_event_t; ++ ++typedef enum dhd_attach_states ++{ ++ DHD_ATTACH_STATE_INIT = 0x0, ++ DHD_ATTACH_STATE_NET_ALLOC = 0x1, ++ DHD_ATTACH_STATE_DHD_ALLOC = 0x2, ++ DHD_ATTACH_STATE_ADD_IF = 0x4, ++ DHD_ATTACH_STATE_PROT_ATTACH = 0x8, ++ DHD_ATTACH_STATE_WL_ATTACH = 0x10, ++ DHD_ATTACH_STATE_THREADS_CREATED = 0x20, ++ DHD_ATTACH_STATE_WAKELOCKS_INIT = 0x40, ++ DHD_ATTACH_STATE_CFG80211 = 0x80, ++ DHD_ATTACH_STATE_EARLYSUSPEND_DONE = 0x100, ++ DHD_ATTACH_STATE_DONE = 0x200 ++} dhd_attach_states_t; ++ ++/* Value -1 means we are unsuccessful in creating the kthread. */ ++#define DHD_PID_KT_INVALID -1 ++/* Value -2 means we are unsuccessful in both creating the kthread and tasklet */ ++#define DHD_PID_KT_TL_INVALID -2 ++ ++/* ++ * Exported from dhd OS modules (dhd_linux/dhd_ndis) ++ */ ++ ++/* To allow osl_attach/detach calls from os-independent modules */ ++osl_t *dhd_osl_attach(void *pdev, uint bustype); ++void dhd_osl_detach(osl_t *osh); ++ ++/* Indication from bus module regarding presence/insertion of dongle. ++ * Return dhd_pub_t pointer, used as handle to OS module in later calls. ++ * Returned structure should have bus and prot pointers filled in. ++ * bus_hdrlen specifies required headroom for bus module header. ++ */ ++extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen); ++#if defined(WLP2P) && defined(WL_CFG80211) ++/* To allow attach/detach calls corresponding to p2p0 interface */ ++extern int dhd_attach_p2p(dhd_pub_t *); ++extern int dhd_detach_p2p(dhd_pub_t *); ++#endif /* WLP2P && WL_CFG80211 */ ++extern int dhd_net_attach(dhd_pub_t *dhdp, int idx); ++ ++/* Indication from bus module regarding removal/absence of dongle */ ++extern void dhd_detach(dhd_pub_t *dhdp); ++extern void dhd_free(dhd_pub_t *dhdp); ++ ++/* Indication from bus module to change flow-control state */ ++extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on); ++ ++extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec); ++ ++/* Receive frame for delivery to OS. Callee disposes of rxp. */ ++extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt, uint8 chan); ++ ++/* Return pointer to interface name */ ++extern char *dhd_ifname(dhd_pub_t *dhdp, int idx); ++ ++/* Request scheduling of the bus dpc */ ++extern void dhd_sched_dpc(dhd_pub_t *dhdp); ++ ++/* Notify tx completion */ ++extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success); ++ ++/* OS independent layer functions */ ++extern int dhd_os_proto_block(dhd_pub_t * pub); ++extern int dhd_os_proto_unblock(dhd_pub_t * pub); ++extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition, bool * pending); ++extern int dhd_os_ioctl_resp_wake(dhd_pub_t * pub); ++extern unsigned int dhd_os_get_ioctl_resp_timeout(void); ++extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec); ++extern void * dhd_os_open_image(char * filename); ++extern int dhd_os_get_image_block(char * buf, int len, void * image); ++extern void dhd_os_close_image(void * image); ++extern void dhd_os_wd_timer(void *bus, uint wdtick); ++extern void dhd_os_sdlock(dhd_pub_t * pub); ++extern void dhd_os_sdunlock(dhd_pub_t * pub); ++extern void dhd_os_sdlock_txq(dhd_pub_t * pub); ++extern void dhd_os_sdunlock_txq(dhd_pub_t * pub); ++extern void dhd_os_sdlock_rxq(dhd_pub_t * pub); ++extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub); ++extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub); ++extern void dhd_customer_gpio_wlan_ctrl(int onoff); ++extern int dhd_custom_get_mac_address(unsigned char *buf); ++extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); ++extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); ++extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); ++extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret); ++extern int dhd_os_send_hang_message(dhd_pub_t *dhdp); ++extern void dhd_set_version_info(dhd_pub_t *pub, char *fw); ++ ++#ifdef PNO_SUPPORT ++extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); ++extern int dhd_pno_clean(dhd_pub_t *dhd); ++extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ++ ushort scan_fr, int pno_repeat, int pno_freq_expo_max); ++extern int dhd_pno_get_status(dhd_pub_t *dhd); ++extern int dhd_dev_pno_reset(struct net_device *dev); ++extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, ++ int nssid, ushort scan_fr, int pno_repeat, int pno_freq_expo_max); ++extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled); ++extern int dhd_dev_get_pno_status(struct net_device *dev); ++#endif /* PNO_SUPPORT */ ++ ++#ifdef PKT_FILTER_SUPPORT ++#define DHD_UNICAST_FILTER_NUM 0 ++#define DHD_BROADCAST_FILTER_NUM 1 ++#define DHD_MULTICAST4_FILTER_NUM 2 ++#define DHD_MULTICAST6_FILTER_NUM 3 ++#define DHD_MDNS_FILTER_NUM 4 ++extern int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val); ++extern void dhd_enable_packet_filter(int value, dhd_pub_t *dhd); ++extern int net_os_enable_packet_filter(struct net_device *dev, int val); ++extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num); ++#endif /* PKT_FILTER_SUPPORT */ ++ ++extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); ++extern bool dhd_support_sta_mode(dhd_pub_t *dhd); ++ ++#ifdef DHD_DEBUG ++extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); ++#endif /* DHD_DEBUG */ ++#if defined(OOB_INTR_ONLY) ++extern int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr); ++#endif ++extern void dhd_os_sdtxlock(dhd_pub_t * pub); ++extern void dhd_os_sdtxunlock(dhd_pub_t * pub); ++ ++typedef struct { ++ uint32 limit; /* Expiration time (usec) */ ++ uint32 increment; /* Current expiration increment (usec) */ ++ uint32 elapsed; /* Current elapsed time (usec) */ ++ uint32 tick; /* O/S tick time (usec) */ ++} dhd_timeout_t; ++ ++extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec); ++extern int dhd_timeout_expired(dhd_timeout_t *tmo); ++ ++extern int dhd_ifname2idx(struct dhd_info *dhd, char *name); ++extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net); ++extern struct net_device * dhd_idx2net(void *pub, int ifidx); ++extern int net_os_send_hang_message(struct net_device *dev); ++extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, ++ wl_event_msg_t *, void **data_ptr); ++extern void wl_event_to_host_order(wl_event_msg_t * evt); ++ ++extern int dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len); ++extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, ++ int ifindex); ++ ++extern void dhd_common_init(osl_t *osh); ++ ++extern int dhd_do_driver_init(struct net_device *net); ++extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle, ++ char *name, uint8 *mac_addr, uint32 flags, uint8 bssidx); ++extern void dhd_del_if(struct dhd_info *dhd, int ifidx); ++ ++extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char * name); ++extern void dhd_vif_del(struct dhd_info *dhd, int ifidx); ++ ++extern void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx); ++extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len); ++ ++ ++/* Send packet to dongle via data channel */ ++extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt); ++ ++/* send up locally generated event */ ++extern void dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); ++/* Send event to host */ ++extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); ++extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag); ++extern uint dhd_bus_status(dhd_pub_t *dhdp); ++extern int dhd_bus_start(dhd_pub_t *dhdp); ++extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size); ++extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line); ++extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval); ++extern uint dhd_bus_chip_id(dhd_pub_t *dhdp); ++extern uint dhd_bus_chiprev_id(dhd_pub_t *dhdp); ++extern uint dhd_bus_chippkg_id(dhd_pub_t *dhdp); ++ ++#if defined(KEEP_ALIVE) ++extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); ++#endif /* KEEP_ALIVE */ ++ ++extern bool dhd_is_concurrent_mode(dhd_pub_t *dhd); ++ ++typedef enum cust_gpio_modes { ++ WLAN_RESET_ON, ++ WLAN_RESET_OFF, ++ WLAN_POWER_ON, ++ WLAN_POWER_OFF ++} cust_gpio_modes_t; ++ ++extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); ++extern int wl_iw_send_priv_event(struct net_device *dev, char *flag); ++/* ++ * Insmod parameters for debug/test ++ */ ++ ++/* Watchdog timer interval */ ++extern uint dhd_watchdog_ms; ++ ++#if defined(DHD_DEBUG) ++/* Console output poll interval */ ++extern uint dhd_console_ms; ++#endif /* defined(DHD_DEBUG) */ ++//extern uint android_msg_level; ++#ifdef CONFIG_WIRELESS_EXT ++extern uint iw_msg_level; ++#endif ++#ifdef WL_CFG80211 ++extern uint wl_dbg_level; ++#endif ++extern uint dhd_slpauto; ++ ++/* Use interrupts */ ++extern uint dhd_intr; ++ ++/* Use polling */ ++extern uint dhd_poll; ++ ++/* ARP offload agent mode */ ++extern uint dhd_arp_mode; ++ ++/* ARP offload enable */ ++extern uint dhd_arp_enable; ++ ++/* Pkt filte enable control */ ++extern uint dhd_pkt_filter_enable; ++ ++/* Pkt filter init setup */ ++extern uint dhd_pkt_filter_init; ++ ++/* Pkt filter mode control */ ++extern uint dhd_master_mode; ++ ++/* Roaming mode control */ ++extern uint dhd_roam_disable; ++ ++/* Roaming mode control */ ++extern uint dhd_radio_up; ++ ++/* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */ ++extern int dhd_idletime; ++#ifdef DHD_USE_IDLECOUNT ++#define DHD_IDLETIME_TICKS 5 ++#else ++#define DHD_IDLETIME_TICKS 1 ++#endif /* DHD_USE_IDLECOUNT */ ++ ++/* SDIO Drive Strength */ ++extern uint dhd_sdiod_drive_strength; ++ ++/* Override to force tx queueing all the time */ ++extern uint dhd_force_tx_queueing; ++/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ ++#define DEFAULT_KEEP_ALIVE_VALUE 55000 /* msec */ ++#ifndef CUSTOM_KEEP_ALIVE_SETTING ++#define CUSTOM_KEEP_ALIVE_SETTING DEFAULT_KEEP_ALIVE_VALUE ++#endif /* DEFAULT_KEEP_ALIVE_VALUE */ ++ ++#define NULL_PKT_STR "null_pkt" ++ ++/* hooks for custom glom setting option via Makefile */ ++#define DEFAULT_GLOM_VALUE -1 ++#ifndef CUSTOM_GLOM_SETTING ++#define CUSTOM_GLOM_SETTING DEFAULT_GLOM_VALUE ++#endif ++ ++/* hooks for custom Roaming Trigger setting via Makefile */ ++#define DEFAULT_ROAM_TRIGGER_VALUE -75 /* dBm default roam trigger all band */ ++#define DEFAULT_ROAM_TRIGGER_SETTING -1 ++#ifndef CUSTOM_ROAM_TRIGGER_SETTING ++#define CUSTOM_ROAM_TRIGGER_SETTING DEFAULT_ROAM_TRIGGER_VALUE ++#endif ++ ++/* hooks for custom Roaming Romaing setting via Makefile */ ++#define DEFAULT_ROAM_DELTA_VALUE 10 /* dBm default roam delta all band */ ++#define DEFAULT_ROAM_DELTA_SETTING -1 ++#ifndef CUSTOM_ROAM_DELTA_SETTING ++#define CUSTOM_ROAM_DELTA_SETTING DEFAULT_ROAM_DELTA_VALUE ++#endif ++ ++/* hooks for custom PNO Event wake lock to guarantee enough time ++ for the Platform to detect Event before system suspended ++*/ ++#define DEFAULT_PNO_EVENT_LOCK_xTIME 2 /* multiplay of DHD_PACKET_TIMEOUT_MS */ ++#ifndef CUSTOM_PNO_EVENT_LOCK_xTIME ++#define CUSTOM_PNO_EVENT_LOCK_xTIME DEFAULT_PNO_EVENT_LOCK_xTIME ++#endif ++ ++/* hooks for custom dhd_dpc_prio setting option via Makefile */ ++#define DEFAULT_DHP_DPC_PRIO 1 ++#ifndef CUSTOM_DPC_PRIO_SETTING ++#define CUSTOM_DPC_PRIO_SETTING DEFAULT_DHP_DPC_PRIO ++#endif ++ ++#define DEFAULT_SUSPEND_BCN_LI_DTIM 3 ++#ifndef CUSTOM_SUSPEND_BCN_LI_DTIM ++#define CUSTOM_SUSPEND_BCN_LI_DTIM DEFAULT_SUSPEND_BCN_LI_DTIM ++#endif ++ ++#ifdef SDTEST ++/* Echo packet generator (SDIO), pkts/s */ ++extern uint dhd_pktgen; ++ ++/* Echo packet len (0 => sawtooth, max 1800) */ ++extern uint dhd_pktgen_len; ++#define MAX_PKTGEN_LEN 1800 ++#endif ++ ++ ++/* optionally set by a module_param_string() */ ++#define MOD_PARAM_PATHLEN 2048 ++extern char fw_path[MOD_PARAM_PATHLEN]; ++extern char nv_path[MOD_PARAM_PATHLEN]; ++ ++#define MOD_PARAM_INFOLEN 512 ++ ++#ifdef SOFTAP ++extern char fw_path2[MOD_PARAM_PATHLEN]; ++#endif ++ ++#define FW_PATH_AUTO_SELECT 1 ++extern char firmware_path[MOD_PARAM_PATHLEN]; ++extern void dhd_bus_select_firmware_name_by_chip(struct dhd_bus *bus, char *dst, char *src); ++#define COPY_FW_PATH_BY_CHIP(bus, dst, src) dhd_bus_select_firmware_name_by_chip(bus, dst, src); ++ ++/* Flag to indicate if we should download firmware on driver load */ ++extern uint dhd_download_fw_on_driverload; ++ ++ ++/* For supporting multiple interfaces */ ++#define DHD_MAX_IFS 16 ++#define DHD_DEL_IF -0xe ++#define DHD_BAD_IF -0xf ++#define WL_AUTO_ROAM_TRIGGER -75 ++ ++#ifdef PROP_TXSTATUS ++/* Please be mindful that total pkttag space is 32 octets only */ ++typedef struct dhd_pkttag { ++ /* ++ b[11 ] - 1 = this packet was sent in response to one time packet request, ++ do not increment credit on status for this one. [WLFC_CTL_TYPE_MAC_REQUEST_PACKET]. ++ b[10 ] - 1 = signal-only-packet to firmware [i.e. nothing to piggyback on] ++ b[9 ] - 1 = packet is host->firmware (transmit direction) ++ - 0 = packet received from firmware (firmware->host) ++ b[8 ] - 1 = packet was sent due to credit_request (pspoll), ++ packet does not count against FIFO credit. ++ - 0 = normal transaction, packet counts against FIFO credit ++ b[7 ] - 1 = AP, 0 = STA ++ b[6:4] - AC FIFO number ++ b[3:0] - interface index ++ */ ++ uint16 if_flags; ++ /* destination MAC address for this packet so that not every ++ module needs to open the packet to find this ++ */ ++ uint8 dstn_ether[ETHER_ADDR_LEN]; ++ /* ++ This 32-bit goes from host to device for every packet. ++ */ ++ uint32 htod_tag; ++ /* bus specific stuff */ ++ union { ++ struct { ++ void* stuff; ++ uint32 thing1; ++ uint32 thing2; ++ } sd; ++ struct { ++ void* bus; ++ void* urb; ++ } usb; ++ } bus_specific; ++} dhd_pkttag_t; ++ ++#define DHD_PKTTAG_SET_H2DTAG(tag, h2dvalue) ((dhd_pkttag_t*)(tag))->htod_tag = (h2dvalue) ++#define DHD_PKTTAG_H2DTAG(tag) (((dhd_pkttag_t*)(tag))->htod_tag) ++ ++#define DHD_PKTTAG_IFMASK 0xf ++#define DHD_PKTTAG_IFTYPE_MASK 0x1 ++#define DHD_PKTTAG_IFTYPE_SHIFT 7 ++#define DHD_PKTTAG_FIFO_MASK 0x7 ++#define DHD_PKTTAG_FIFO_SHIFT 4 ++ ++#define DHD_PKTTAG_SIGNALONLY_MASK 0x1 ++#define DHD_PKTTAG_SIGNALONLY_SHIFT 10 ++ ++#define DHD_PKTTAG_ONETIMEPKTRQST_MASK 0x1 ++#define DHD_PKTTAG_ONETIMEPKTRQST_SHIFT 11 ++ ++#define DHD_PKTTAG_PKTDIR_MASK 0x1 ++#define DHD_PKTTAG_PKTDIR_SHIFT 9 ++ ++#define DHD_PKTTAG_CREDITCHECK_MASK 0x1 ++#define DHD_PKTTAG_CREDITCHECK_SHIFT 8 ++ ++#define DHD_PKTTAG_INVALID_FIFOID 0x7 ++ ++#define DHD_PKTTAG_SETFIFO(tag, fifo) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_FIFO_MASK << DHD_PKTTAG_FIFO_SHIFT)) | \ ++ (((fifo) & DHD_PKTTAG_FIFO_MASK) << DHD_PKTTAG_FIFO_SHIFT) ++#define DHD_PKTTAG_FIFO(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_FIFO_SHIFT) & DHD_PKTTAG_FIFO_MASK) ++ ++#define DHD_PKTTAG_SETIF(tag, if) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & ~DHD_PKTTAG_IFMASK) | ((if) & DHD_PKTTAG_IFMASK) ++#define DHD_PKTTAG_IF(tag) (((dhd_pkttag_t*)(tag))->if_flags & DHD_PKTTAG_IFMASK) ++ ++#define DHD_PKTTAG_SETIFTYPE(tag, isAP) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_IFTYPE_MASK << DHD_PKTTAG_IFTYPE_SHIFT)) | \ ++ (((isAP) & DHD_PKTTAG_IFTYPE_MASK) << DHD_PKTTAG_IFTYPE_SHIFT) ++#define DHD_PKTTAG_IFTYPE(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_IFTYPE_SHIFT) & DHD_PKTTAG_IFTYPE_MASK) ++ ++#define DHD_PKTTAG_SETCREDITCHECK(tag, check) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_CREDITCHECK_MASK << DHD_PKTTAG_CREDITCHECK_SHIFT)) | \ ++ (((check) & DHD_PKTTAG_CREDITCHECK_MASK) << DHD_PKTTAG_CREDITCHECK_SHIFT) ++#define DHD_PKTTAG_CREDITCHECK(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_CREDITCHECK_SHIFT) & DHD_PKTTAG_CREDITCHECK_MASK) ++ ++#define DHD_PKTTAG_SETPKTDIR(tag, dir) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_PKTDIR_MASK << DHD_PKTTAG_PKTDIR_SHIFT)) | \ ++ (((dir) & DHD_PKTTAG_PKTDIR_MASK) << DHD_PKTTAG_PKTDIR_SHIFT) ++#define DHD_PKTTAG_PKTDIR(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_PKTDIR_SHIFT) & DHD_PKTTAG_PKTDIR_MASK) ++ ++#define DHD_PKTTAG_SETSIGNALONLY(tag, signalonly) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_SIGNALONLY_MASK << DHD_PKTTAG_SIGNALONLY_SHIFT)) | \ ++ (((signalonly) & DHD_PKTTAG_SIGNALONLY_MASK) << DHD_PKTTAG_SIGNALONLY_SHIFT) ++#define DHD_PKTTAG_SIGNALONLY(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_SIGNALONLY_SHIFT) & DHD_PKTTAG_SIGNALONLY_MASK) ++ ++#define DHD_PKTTAG_SETONETIMEPKTRQST(tag) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_ONETIMEPKTRQST_MASK << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT)) | \ ++ (1 << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) ++#define DHD_PKTTAG_ONETIMEPKTRQST(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) & DHD_PKTTAG_ONETIMEPKTRQST_MASK) ++ ++#define DHD_PKTTAG_SETDSTN(tag, dstn_MAC_ea) memcpy(((dhd_pkttag_t*)((tag)))->dstn_ether, \ ++ (dstn_MAC_ea), ETHER_ADDR_LEN) ++#define DHD_PKTTAG_DSTN(tag) ((dhd_pkttag_t*)(tag))->dstn_ether ++ ++typedef int (*f_commitpkt_t)(void* ctx, void* p, bool wlfc_locked); ++ ++#ifdef PROP_TXSTATUS_DEBUG ++#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do { (entry)->closed_ct++; } while (0) ++#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do { (entry)->opened_ct++; } while (0) ++#else ++#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do {} while (0) ++#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do {} while (0) ++#endif ++ ++#endif /* PROP_TXSTATUS */ ++ ++extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar); ++extern void dhd_wait_event_wakeup(dhd_pub_t*dhd); ++ ++#define IFLOCK_INIT(lock) *lock = 0 ++#define IFLOCK(lock) while (InterlockedCompareExchange((lock), 1, 0)) \ ++ NdisStallExecution(1); ++#define IFUNLOCK(lock) InterlockedExchange((lock), 0) ++#define IFLOCK_FREE(lock) ++ ++#ifdef PNO_SUPPORT ++extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); ++extern int dhd_pnoenable(dhd_pub_t *dhd, int pfn_enabled); ++extern int dhd_pno_clean(dhd_pub_t *dhd); ++extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ++ ushort scan_fr, int pno_repeat, int pno_freq_expo_max); ++extern int dhd_pno_get_status(dhd_pub_t *dhd); ++extern int dhd_pno_set_add(dhd_pub_t *dhd, wl_pfn_t *netinfo, int nssid, ushort scan_fr, ++ ushort slowscan_fr, uint8 pno_repeat, uint8 pno_freq_expo_max, int16 flags); ++extern int dhd_pno_cfg(dhd_pub_t *dhd, wl_pfn_cfg_t *pcfg); ++extern int dhd_pno_suspend(dhd_pub_t *dhd, int pfn_suspend); ++#endif /* PNO_SUPPORT */ ++#ifdef ARP_OFFLOAD_SUPPORT ++#define MAX_IPV4_ENTRIES 8 ++void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode); ++void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable); ++ ++/* dhd_commn arp offload wrapers */ ++void dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx); ++void dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx); ++int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx); ++void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx); ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++#endif /* _dhd_h_ */ +diff --git a/drivers/net/wireless/ap6211/dhd_bta.c b/drivers/net/wireless/ap6211/dhd_bta.c +new file mode 100755 +index 0000000..3752bbd +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_bta.c +@@ -0,0 +1,338 @@ ++/* ++ * BT-AMP support routines ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_bta.c 303834 2011-12-20 06:17:39Z $ ++ */ ++#ifndef WLBTAMP ++#error "WLBTAMP is not defined" ++#endif /* WLBTAMP */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++ ++#ifdef SEND_HCI_CMD_VIA_IOCTL ++#define BTA_HCI_CMD_MAX_LEN HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE ++ ++/* Send HCI cmd via wl iovar HCI_cmd to the dongle. */ ++int ++dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) ++{ ++ amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; ++ uint8 buf[BTA_HCI_CMD_MAX_LEN + 16]; ++ uint len = sizeof(buf); ++ wl_ioctl_t ioc; ++ ++ if (cmd_len < HCI_CMD_PREAMBLE_SIZE) ++ return BCME_BADLEN; ++ ++ if ((uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE > cmd_len) ++ return BCME_BADLEN; ++ ++ len = bcm_mkiovar("HCI_cmd", ++ (char *)cmd, (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, (char *)buf, len); ++ ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ++ ioc.cmd = WLC_SET_VAR; ++ ioc.buf = buf; ++ ioc.len = len; ++ ioc.set = TRUE; ++ ++ return dhd_wl_ioctl(pub, &ioc, ioc.buf, ioc.len); ++} ++#else /* !SEND_HCI_CMD_VIA_IOCTL */ ++ ++static void ++dhd_bta_flush_hcidata(dhd_pub_t *pub, uint16 llh) ++{ ++ int prec; ++ struct pktq *q; ++ uint count = 0; ++ ++ q = dhd_bus_txq(pub->bus); ++ if (q == NULL) ++ return; ++ ++ DHD_BTA(("dhd: flushing HCI ACL data for logical link %u...\n", llh)); ++ ++ dhd_os_sdlock_txq(pub); ++ ++ /* Walk through the txq and toss all HCI ACL data packets */ ++ PKTQ_PREC_ITER(q, prec) { ++ void *head_pkt = NULL; ++ ++ while (pktq_ppeek(q, prec) != head_pkt) { ++ void *pkt = pktq_pdeq(q, prec); ++ int ifidx; ++ ++ PKTPULL(pub->osh, pkt, dhd_bus_hdrlen(pub->bus)); ++ dhd_prot_hdrpull(pub, &ifidx, pkt, NULL, NULL); ++ ++ if (PKTLEN(pub->osh, pkt) >= RFC1042_HDR_LEN) { ++ struct ether_header *eh = ++ (struct ether_header *)PKTDATA(pub->osh, pkt); ++ ++ if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) { ++ struct dot11_llc_snap_header *lsh = ++ (struct dot11_llc_snap_header *)&eh[1]; ++ ++ if (bcmp(lsh, BT_SIG_SNAP_MPROT, ++ DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && ++ ntoh16(lsh->type) == BTA_PROT_L2CAP) { ++ amp_hci_ACL_data_t *ACL_data = ++ (amp_hci_ACL_data_t *)&lsh[1]; ++ uint16 handle = ltoh16(ACL_data->handle); ++ ++ if (HCI_ACL_DATA_HANDLE(handle) == llh) { ++ PKTFREE(pub->osh, pkt, TRUE); ++ count ++; ++ continue; ++ } ++ } ++ } ++ } ++ ++ dhd_prot_hdrpush(pub, ifidx, pkt); ++ PKTPUSH(pub->osh, pkt, dhd_bus_hdrlen(pub->bus)); ++ ++ if (head_pkt == NULL) ++ head_pkt = pkt; ++ pktq_penq(q, prec, pkt); ++ } ++ } ++ ++ dhd_os_sdunlock_txq(pub); ++ ++ DHD_BTA(("dhd: flushed %u packet(s) for logical link %u...\n", count, llh)); ++} ++ ++/* Handle HCI cmd locally. ++ * Return 0: continue to send the cmd across SDIO ++ * < 0: stop, fail ++ * > 0: stop, succuess ++ */ ++static int ++_dhd_bta_docmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd) ++{ ++ int status = 0; ++ ++ switch (ltoh16_ua((uint8 *)&cmd->opcode)) { ++ case HCI_Enhanced_Flush: { ++ eflush_cmd_parms_t *cmdparms = (eflush_cmd_parms_t *)cmd->parms; ++ dhd_bta_flush_hcidata(pub, ltoh16_ua(cmdparms->llh)); ++ break; ++ } ++ default: ++ break; ++ } ++ ++ return status; ++} ++ ++/* Send HCI cmd encapsulated in BT-SIG frame via data channel to the dongle. */ ++int ++dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) ++{ ++ amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; ++ struct ether_header *eh; ++ struct dot11_llc_snap_header *lsh; ++ osl_t *osh = pub->osh; ++ uint len; ++ void *p; ++ int status; ++ ++ if (cmd_len < HCI_CMD_PREAMBLE_SIZE) { ++ AP6211_ERR("dhd_bta_docmd: short command, cmd_len %u\n", cmd_len); ++ return BCME_BADLEN; ++ } ++ ++ if ((len = (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE) > cmd_len) { ++ AP6211_ERR("dhd_bta_docmd: malformed command, len %u cmd_len %u\n", ++ len, cmd_len); ++ /* return BCME_BADLEN; */ ++ } ++ ++ p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); ++ if (p == NULL) { ++ AP6211_ERR("dhd_bta_docmd: out of memory\n"); ++ return BCME_NOMEM; ++ } ++ ++ ++ /* intercept and handle the HCI cmd locally */ ++ if ((status = _dhd_bta_docmd(pub, cmd)) > 0) ++ return 0; ++ else if (status < 0) ++ return status; ++ ++ /* copy in HCI cmd */ ++ PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); ++ bcopy(cmd, PKTDATA(osh, p), len); ++ ++ /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ ++ PKTPUSH(osh, p, RFC1042_HDR_LEN); ++ eh = (struct ether_header *)PKTDATA(osh, p); ++ bzero(eh->ether_dhost, ETHER_ADDR_LEN); ++ ETHER_SET_LOCALADDR(eh->ether_dhost); ++ bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); ++ eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); ++ lsh = (struct dot11_llc_snap_header *)&eh[1]; ++ bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); ++ lsh->type = 0; ++ ++ return dhd_sendpkt(pub, 0, p); ++} ++#endif /* !SEND_HCI_CMD_VIA_IOCTL */ ++ ++/* Send HCI ACL data to dongle via data channel */ ++int ++dhd_bta_tx_hcidata(dhd_pub_t *pub, void *data_buf, uint data_len) ++{ ++ amp_hci_ACL_data_t *data = (amp_hci_ACL_data_t *)data_buf; ++ struct ether_header *eh; ++ struct dot11_llc_snap_header *lsh; ++ osl_t *osh = pub->osh; ++ uint len; ++ void *p; ++ ++ if (data_len < HCI_ACL_DATA_PREAMBLE_SIZE) { ++ AP6211_ERR("dhd_bta_tx_hcidata: short data_buf, data_len %u\n", data_len); ++ return BCME_BADLEN; ++ } ++ ++ if ((len = (uint)ltoh16(data->dlen) + HCI_ACL_DATA_PREAMBLE_SIZE) > data_len) { ++ AP6211_ERR("dhd_bta_tx_hcidata: malformed hci data, len %u data_len %u\n", ++ len, data_len); ++ /* return BCME_BADLEN; */ ++ } ++ ++ p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); ++ if (p == NULL) { ++ AP6211_ERR("dhd_bta_tx_hcidata: out of memory\n"); ++ return BCME_NOMEM; ++ } ++ ++ ++ /* copy in HCI ACL data header and HCI ACL data */ ++ PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); ++ bcopy(data, PKTDATA(osh, p), len); ++ ++ /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ ++ PKTPUSH(osh, p, RFC1042_HDR_LEN); ++ eh = (struct ether_header *)PKTDATA(osh, p); ++ bzero(eh->ether_dhost, ETHER_ADDR_LEN); ++ bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); ++ eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); ++ lsh = (struct dot11_llc_snap_header *)&eh[1]; ++ bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); ++ lsh->type = HTON16(BTA_PROT_L2CAP); ++ ++ return dhd_sendpkt(pub, 0, p); ++} ++ ++/* txcomplete callback */ ++void ++dhd_bta_tx_hcidata_complete(dhd_pub_t *dhdp, void *txp, bool success) ++{ ++ uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, txp); ++ amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)(pktdata + RFC1042_HDR_LEN); ++ uint16 handle = ltoh16(ACL_data->handle); ++ uint16 llh = HCI_ACL_DATA_HANDLE(handle); ++ ++ wl_event_msg_t event; ++ uint8 data[HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t)]; ++ amp_hci_event_t *evt; ++ num_completed_data_blocks_evt_parms_t *parms; ++ ++ uint16 len = HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t); ++ ++ /* update the event struct */ ++ memset(&event, 0, sizeof(event)); ++ event.version = hton16(BCM_EVENT_MSG_VERSION); ++ event.event_type = hton32(WLC_E_BTA_HCI_EVENT); ++ event.status = 0; ++ event.reason = 0; ++ event.auth_type = 0; ++ event.datalen = hton32(len); ++ event.flags = 0; ++ ++ /* generate Number of Completed Blocks event */ ++ evt = (amp_hci_event_t *)data; ++ evt->ecode = HCI_Number_of_Completed_Data_Blocks; ++ evt->plen = sizeof(num_completed_data_blocks_evt_parms_t); ++ ++ parms = (num_completed_data_blocks_evt_parms_t *)evt->parms; ++ htol16_ua_store(dhdp->maxdatablks, (uint8 *)&parms->num_blocks); ++ parms->num_handles = 1; ++ htol16_ua_store(llh, (uint8 *)&parms->completed[0].handle); ++ parms->completed[0].pkts = 1; ++ parms->completed[0].blocks = 1; ++ ++ dhd_sendup_event_common(dhdp, &event, data); ++} ++ ++/* event callback */ ++void ++dhd_bta_doevt(dhd_pub_t *dhdp, void *data_buf, uint data_len) ++{ ++ amp_hci_event_t *evt = (amp_hci_event_t *)data_buf; ++ ++ switch (evt->ecode) { ++ case HCI_Command_Complete: { ++ cmd_complete_parms_t *parms = (cmd_complete_parms_t *)evt->parms; ++ switch (ltoh16_ua((uint8 *)&parms->opcode)) { ++ case HCI_Read_Data_Block_Size: { ++ read_data_block_size_evt_parms_t *parms2 = ++ (read_data_block_size_evt_parms_t *)parms->parms; ++ dhdp->maxdatablks = ltoh16_ua((uint8 *)&parms2->data_block_num); ++ break; ++ } ++ } ++ break; ++ } ++ ++ case HCI_Flush_Occurred: { ++ flush_occurred_evt_parms_t *evt_parms = (flush_occurred_evt_parms_t *)evt->parms; ++ dhd_bta_flush_hcidata(dhdp, ltoh16_ua((uint8 *)&evt_parms->handle)); ++ break; ++ } ++ default: ++ break; ++ } ++} +diff --git a/drivers/net/wireless/ap6211/dhd_bta.h b/drivers/net/wireless/ap6211/dhd_bta.h +new file mode 100755 +index 0000000..0337f15 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_bta.h +@@ -0,0 +1,39 @@ ++/* ++ * BT-AMP support routines ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_bta.h 291086 2011-10-21 01:17:24Z $ ++ */ ++#ifndef __dhd_bta_h__ ++#define __dhd_bta_h__ ++ ++struct dhd_pub; ++ ++extern int dhd_bta_docmd(struct dhd_pub *pub, void *cmd_buf, uint cmd_len); ++ ++extern void dhd_bta_doevt(struct dhd_pub *pub, void *data_buf, uint data_len); ++ ++extern int dhd_bta_tx_hcidata(struct dhd_pub *pub, void *data_buf, uint data_len); ++extern void dhd_bta_tx_hcidata_complete(struct dhd_pub *dhdp, void *txp, bool success); ++ ++ ++#endif /* __dhd_bta_h__ */ +diff --git a/drivers/net/wireless/ap6211/dhd_bus.h b/drivers/net/wireless/ap6211/dhd_bus.h +new file mode 100755 +index 0000000..131907d +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_bus.h +@@ -0,0 +1,111 @@ ++/* ++ * Header file describing the internal (inter-module) DHD interfaces. ++ * ++ * Provides type definitions and function prototypes used to link the ++ * DHD OS, bus, and protocol modules. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_bus.h 347614 2012-07-27 10:24:51Z $ ++ */ ++ ++#ifndef _dhd_bus_h_ ++#define _dhd_bus_h_ ++ ++/* ++ * Exported from dhd bus module (dhd_usb, dhd_sdio) ++ */ ++ ++/* Indicate (dis)interest in finding dongles. */ ++extern int dhd_bus_register(void); ++extern void dhd_bus_unregister(void); ++ ++/* Download firmware image and nvram image */ ++extern bool dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, ++ char *fw_path, char *nv_path); ++ ++/* Stop bus module: clear pending frames, disable data flow */ ++extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex); ++ ++/* Initialize bus module: prepare for communication w/dongle */ ++extern int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex); ++ ++/* Get the Bus Idle Time */ ++extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int *idletime); ++ ++/* Set the Bus Idle Time */ ++extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time); ++ ++/* Send a data frame to the dongle. Callee disposes of txp. */ ++extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp, bool wlfc_locked); ++ ++/* Send/receive a control message to/from the dongle. ++ * Expects caller to enforce a single outstanding transaction. ++ */ ++extern int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen); ++extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen); ++ ++/* Watchdog timer function */ ++extern bool dhd_bus_watchdog(dhd_pub_t *dhd); ++extern void dhd_disable_intr(dhd_pub_t *dhd); ++ ++#if defined(DHD_DEBUG) ++/* Device console input function */ ++extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen); ++#endif /* defined(DHD_DEBUG) */ ++ ++/* Deferred processing for the bus, return TRUE requests reschedule */ ++extern bool dhd_bus_dpc(struct dhd_bus *bus); ++extern void dhd_bus_isr(bool * InterruptRecognized, bool * QueueMiniportHandleInterrupt, void *arg); ++ ++ ++/* Check for and handle local prot-specific iovar commands */ ++extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, ++ void *params, int plen, void *arg, int len, bool set); ++ ++/* Add bus dump output to a buffer */ ++extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); ++ ++/* Clear any bus counters */ ++extern void dhd_bus_clearcounts(dhd_pub_t *dhdp); ++ ++/* return the dongle chipid */ ++extern uint dhd_bus_chip(struct dhd_bus *bus); ++ ++/* Set user-specified nvram parameters. */ ++extern void dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params); ++ ++extern void *dhd_bus_pub(struct dhd_bus *bus); ++extern void *dhd_bus_txq(struct dhd_bus *bus); ++extern uint dhd_bus_hdrlen(struct dhd_bus *bus); ++ ++ ++#define DHD_SET_BUS_STATE_DOWN(_bus) do { \ ++ (_bus)->dhd->busstate = DHD_BUS_DOWN; \ ++} while (0) ++ ++/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ ++extern int dhd_bus_reg_sdio_notify(void* semaphore); ++extern void dhd_bus_unreg_sdio_notify(void); ++ ++extern void dhd_txglom_enable(dhd_pub_t *dhdp, bool enable); ++ ++#endif /* _dhd_bus_h_ */ +diff --git a/drivers/net/wireless/ap6211/dhd_cdc.c b/drivers/net/wireless/ap6211/dhd_cdc.c +new file mode 100755 +index 0000000..3a7f55b +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_cdc.c +@@ -0,0 +1,3191 @@ ++/* ++ * DHD Protocol Module for CDC and BDC. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_cdc.c 368762 2012-11-14 21:59:17Z $ ++ * ++ * BDC is like CDC, except it includes a header for data packets to convey ++ * packet priority over the bus, and flags (e.g. to indicate checksum status ++ * for dongle offload.) ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++#ifdef PROP_TXSTATUS ++#include ++#include ++#endif ++ ++#include ++ ++#define RETRIES 2 /* # of retries to retrieve matching ioctl response */ ++#define BUS_HEADER_LEN (24+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE ++ * defined in dhd_sdio.c (amount of header tha might be added) ++ * plus any space that might be needed for alignment padding. ++ */ ++#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for ++ * round off at the end of buffer ++ */ ++ ++#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */ ++ ++#ifdef PROP_TXSTATUS ++typedef struct dhd_wlfc_commit_info { ++ uint8 needs_hdr; ++ uint8 ac_fifo_credit_spent; ++ ewlfc_packet_state_t pkt_type; ++ wlfc_mac_descriptor_t* mac_entry; ++ void* p; ++} dhd_wlfc_commit_info_t; ++#endif /* PROP_TXSTATUS */ ++ ++ ++typedef struct dhd_prot { ++ uint16 reqid; ++ uint8 pending; ++ uint32 lastcmd; ++ uint8 bus_header[BUS_HEADER_LEN]; ++ cdc_ioctl_t msg; ++ unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN]; ++} dhd_prot_t; ++ ++ ++static int ++dhdcdc_msg(dhd_pub_t *dhd) ++{ ++ int err = 0; ++ dhd_prot_t *prot = dhd->prot; ++ int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t); ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ DHD_OS_WAKE_LOCK(dhd); ++ ++ /* NOTE : cdc->msg.len holds the desired length of the buffer to be ++ * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area ++ * is actually sent to the dongle ++ */ ++ if (len > CDC_MAX_MSG_SIZE) ++ len = CDC_MAX_MSG_SIZE; ++ ++ /* Send request */ ++ err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); ++ ++ DHD_OS_WAKE_UNLOCK(dhd); ++ return err; ++} ++ ++static int ++dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) ++{ ++ int ret; ++ int cdc_len = len + sizeof(cdc_ioctl_t); ++ dhd_prot_t *prot = dhd->prot; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ do { ++ ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len); ++ if (ret < 0) ++ break; ++ } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id); ++ ++ return ret; ++} ++ ++static int ++dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ cdc_ioctl_t *msg = &prot->msg; ++ void *info; ++ int ret = 0, retries = 0; ++ uint32 id, flags = 0; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ AP6211_DEBUG("%s: cmd %d len %d\n", __FUNCTION__, cmd, len); ++ ++ ++ /* Respond "bcmerror" and "bcmerrorstr" with local cache */ ++ if (cmd == WLC_GET_VAR && buf) ++ { ++ if (!strcmp((char *)buf, "bcmerrorstr")) ++ { ++ strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN); ++ goto done; ++ } ++ else if (!strcmp((char *)buf, "bcmerror")) ++ { ++ *(int *)buf = dhd->dongle_error; ++ goto done; ++ } ++ } ++ ++ memset(msg, 0, sizeof(cdc_ioctl_t)); ++ ++ msg->cmd = htol32(cmd); ++ msg->len = htol32(len); ++ msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); ++ CDC_SET_IF_IDX(msg, ifidx); ++ /* add additional action bits */ ++ action &= WL_IOCTL_ACTION_MASK; ++ msg->flags |= (action << CDCF_IOC_ACTION_SHIFT); ++ msg->flags = htol32(msg->flags); ++ ++ if (buf) ++ memcpy(prot->buf, buf, len); ++ ++ if ((ret = dhdcdc_msg(dhd)) < 0) { ++ if (!dhd->hang_was_sent) ++ AP6211_ERR("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret); ++ goto done; ++ } ++ ++retry: ++ /* wait for interrupt and get first fragment */ ++ if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) ++ goto done; ++ ++ flags = ltoh32(msg->flags); ++ id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; ++ ++ if ((id < prot->reqid) && (++retries < RETRIES)) ++ goto retry; ++ if (id != prot->reqid) { ++ AP6211_ERR("%s: %s: unexpected request id %d (expected %d)\n", ++ dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ /* Check info buffer */ ++ info = (void*)&msg[1]; ++ ++ /* Copy info buffer */ ++ if (buf) ++ { ++ if (ret < (int)len) ++ len = ret; ++ memcpy(buf, info, len); ++ } ++ ++ /* Check the ERROR flag */ ++ if (flags & CDCF_IOC_ERROR) ++ { ++ ret = ltoh32(msg->status); ++ /* Cache error from dongle */ ++ dhd->dongle_error = ret; ++ } ++ ++done: ++ return ret; ++} ++ ++static int ++dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ cdc_ioctl_t *msg = &prot->msg; ++ int ret = 0; ++ uint32 flags, id; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ AP6211_DEBUG("%s: cmd %d len %d\n", __FUNCTION__, cmd, len); ++ ++ if (dhd->busstate == DHD_BUS_DOWN) { ++ AP6211_ERR("%s : bus is down. we have nothing to do\n", __FUNCTION__); ++ return -EIO; ++ } ++ ++ /* don't talk to the dongle if fw is about to be reloaded */ ++ if (dhd->hang_was_sent) { ++ AP6211_ERR("%s: HANG was sent up earlier. Not talking to the chip\n", ++ __FUNCTION__); ++ return -EIO; ++ } ++ ++ memset(msg, 0, sizeof(cdc_ioctl_t)); ++ ++ msg->cmd = htol32(cmd); ++ msg->len = htol32(len); ++ msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); ++ CDC_SET_IF_IDX(msg, ifidx); ++ /* add additional action bits */ ++ action &= WL_IOCTL_ACTION_MASK; ++ msg->flags |= (action << CDCF_IOC_ACTION_SHIFT) | CDCF_IOC_SET; ++ msg->flags = htol32(msg->flags); ++ ++ if (buf) ++ memcpy(prot->buf, buf, len); ++ ++ if ((ret = dhdcdc_msg(dhd)) < 0) { ++ AP6211_ERR("%s: dhdcdc_msg failed w/status %d\n", __FUNCTION__, ret); ++ goto done; ++ } ++ ++ if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) ++ goto done; ++ ++ flags = ltoh32(msg->flags); ++ id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; ++ ++ if (id != prot->reqid) { ++ AP6211_ERR("%s: %s: unexpected request id %d (expected %d)\n", ++ dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ /* Check the ERROR flag */ ++ if (flags & CDCF_IOC_ERROR) ++ { ++ ret = ltoh32(msg->status); ++ /* Cache error from dongle */ ++ dhd->dongle_error = ret; ++ } ++ ++done: ++ return ret; ++} ++ ++ ++int ++dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ int ret = -1; ++ uint8 action; ++#if defined(NDIS630) ++ bool acquired = FALSE; ++#endif ++ ++ if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) { ++ AP6211_ERR("%s : bus is down. we have nothing to do\n", __FUNCTION__); ++ goto done; ++ } ++#if defined(NDIS630) ++ if (dhd_os_proto_block(dhd)) ++ { ++ acquired = TRUE; ++ } ++ else ++ { ++ /* attempt to acquire protocol mutex timed out. */ ++ ret = -1; ++ return ret; ++ } ++#endif /* NDIS630 */ ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ ASSERT(len <= WLC_IOCTL_MAXLEN); ++ ++ if (len > WLC_IOCTL_MAXLEN) ++ goto done; ++ ++ if (prot->pending == TRUE) { ++ AP6211_ERR("CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n", ++ ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd, ++ (unsigned long)prot->lastcmd); ++ if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) { ++ AP6211_DEBUG("iovar cmd=%s\n", (char*)buf); ++ } ++ goto done; ++ } ++ ++ prot->pending = TRUE; ++ prot->lastcmd = ioc->cmd; ++ action = ioc->set; ++ if (action & WL_IOCTL_ACTION_SET) ++ ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); ++ else { ++ ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); ++ if (ret > 0) ++ ioc->used = ret - sizeof(cdc_ioctl_t); ++ } ++ ++ /* Too many programs assume ioctl() returns 0 on success */ ++ if (ret >= 0) ++ ret = 0; ++ else { ++ cdc_ioctl_t *msg = &prot->msg; ++ ioc->needed = ltoh32(msg->len); /* len == needed when set/query fails from dongle */ ++ } ++ ++ /* Intercept the wme_dp ioctl here */ ++ if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) { ++ int slen, val = 0; ++ ++ slen = strlen("wme_dp") + 1; ++ if (len >= (int)(slen + sizeof(int))) ++ bcopy(((char *)buf + slen), &val, sizeof(int)); ++ dhd->wme_dp = (uint8) ltoh32(val); ++ } ++ ++ prot->pending = FALSE; ++ ++done: ++#if defined(NDIS630) ++ if (acquired) ++ dhd_os_proto_unblock(dhd); ++#endif ++ return ret; ++} ++ ++int ++dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ return BCME_UNSUPPORTED; ++} ++ ++#ifdef PROP_TXSTATUS ++void ++dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) ++{ ++ int i; ++ uint8* ea; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhdp->wlfc_state; ++ wlfc_hanger_t* h; ++ wlfc_mac_descriptor_t* mac_table; ++ wlfc_mac_descriptor_t* interfaces; ++ char* iftypes[] = {"STA", "AP", "WDS", "p2pGO", "p2pCL"}; ++ ++ if (wlfc == NULL) { ++ bcm_bprintf(strbuf, "wlfc not initialized yet\n"); ++ return; ++ } ++ h = (wlfc_hanger_t*)wlfc->hanger; ++ if (h == NULL) { ++ bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); ++ } ++ ++ mac_table = wlfc->destination_entries.nodes; ++ interfaces = wlfc->destination_entries.interfaces; ++ bcm_bprintf(strbuf, "---- wlfc stats ----\n"); ++ if (h) { ++ bcm_bprintf(strbuf, "wlfc hanger (pushed,popped,f_push," ++ "f_pop,f_slot, pending) = (%d,%d,%d,%d,%d,%d)\n", ++ h->pushed, ++ h->popped, ++ h->failed_to_push, ++ h->failed_to_pop, ++ h->failed_slotfind, ++ (h->pushed - h->popped)); ++ } ++ ++ bcm_bprintf(strbuf, "wlfc fail(tlv,credit_rqst,mac_update,psmode_update), " ++ "(dq_full,sendq_full, rollback_fail) = (%d,%d,%d,%d), (%d,%d,%d)\n", ++ wlfc->stats.tlv_parse_failed, ++ wlfc->stats.credit_request_failed, ++ wlfc->stats.mac_update_failed, ++ wlfc->stats.psmode_update_failed, ++ wlfc->stats.delayq_full_error, ++ wlfc->stats.sendq_full_error, ++ wlfc->stats.rollback_failed); ++ ++ bcm_bprintf(strbuf, "SENDQ (len,credit,sent) " ++ "(AC0[%d,%d,%d],AC1[%d,%d,%d],AC2[%d,%d,%d],AC3[%d,%d,%d],BC_MC[%d,%d,%d])\n", ++ wlfc->SENDQ.q[0].len, wlfc->FIFO_credit[0], wlfc->stats.sendq_pkts[0], ++ wlfc->SENDQ.q[1].len, wlfc->FIFO_credit[1], wlfc->stats.sendq_pkts[1], ++ wlfc->SENDQ.q[2].len, wlfc->FIFO_credit[2], wlfc->stats.sendq_pkts[2], ++ wlfc->SENDQ.q[3].len, wlfc->FIFO_credit[3], wlfc->stats.sendq_pkts[3], ++ wlfc->SENDQ.q[4].len, wlfc->FIFO_credit[4], wlfc->stats.sendq_pkts[4]); ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ bcm_bprintf(strbuf, "SENDQ dropped: AC[0-3]:(%d,%d,%d,%d), (bcmc,atim):(%d,%d)\n", ++ wlfc->stats.dropped_qfull[0], wlfc->stats.dropped_qfull[1], ++ wlfc->stats.dropped_qfull[2], wlfc->stats.dropped_qfull[3], ++ wlfc->stats.dropped_qfull[4], wlfc->stats.dropped_qfull[5]); ++#endif ++ ++ bcm_bprintf(strbuf, "\n"); ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ if (interfaces[i].occupied) { ++ char* iftype_desc; ++ ++ if (interfaces[i].iftype > WLC_E_IF_ROLE_P2P_CLIENT) ++ iftype_desc = "hostif_flow_state[i] == OFF) ++ ? " OFF":" ON")); ++ ++ bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ(len,state,credit)" ++ "= (%d,%s,%d)\n", ++ i, ++ interfaces[i].psq.len, ++ ((interfaces[i].state == ++ WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), ++ interfaces[i].requested_credit); ++ ++ bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ" ++ "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " ++ "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", ++ i, ++ interfaces[i].psq.q[0].len, ++ interfaces[i].psq.q[1].len, ++ interfaces[i].psq.q[2].len, ++ interfaces[i].psq.q[3].len, ++ interfaces[i].psq.q[4].len, ++ interfaces[i].psq.q[5].len, ++ interfaces[i].psq.q[6].len, ++ interfaces[i].psq.q[7].len); ++ } ++ } ++ ++ bcm_bprintf(strbuf, "\n"); ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (mac_table[i].occupied) { ++ ea = mac_table[i].ea; ++ bcm_bprintf(strbuf, "MAC_table[%d].ea = " ++ "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d \n", i, ++ ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], ++ mac_table[i].interface_id); ++ ++ bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ(len,state,credit)" ++ "= (%d,%s,%d)\n", ++ i, ++ mac_table[i].psq.len, ++ ((mac_table[i].state == ++ WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), ++ mac_table[i].requested_credit); ++#ifdef PROP_TXSTATUS_DEBUG ++ bcm_bprintf(strbuf, "MAC_table[%d]: (opened, closed) = (%d, %d)\n", ++ i, mac_table[i].opened_ct, mac_table[i].closed_ct); ++#endif ++ bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ" ++ "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " ++ "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", ++ i, ++ mac_table[i].psq.q[0].len, ++ mac_table[i].psq.q[1].len, ++ mac_table[i].psq.q[2].len, ++ mac_table[i].psq.q[3].len, ++ mac_table[i].psq.q[4].len, ++ mac_table[i].psq.q[5].len, ++ mac_table[i].psq.q[6].len, ++ mac_table[i].psq.q[7].len); ++ } ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ int avg; ++ int moving_avg = 0; ++ int moving_samples; ++ ++ if (wlfc->stats.latency_sample_count) { ++ moving_samples = sizeof(wlfc->stats.deltas)/sizeof(uint32); ++ ++ for (i = 0; i < moving_samples; i++) ++ moving_avg += wlfc->stats.deltas[i]; ++ moving_avg /= moving_samples; ++ ++ avg = (100 * wlfc->stats.total_status_latency) / ++ wlfc->stats.latency_sample_count; ++ bcm_bprintf(strbuf, "txstatus latency (average, last, moving[%d]) = " ++ "(%d.%d, %03d, %03d)\n", ++ moving_samples, avg/100, (avg - (avg/100)*100), ++ wlfc->stats.latency_most_recent, ++ moving_avg); ++ } ++ } ++ ++ bcm_bprintf(strbuf, "wlfc- fifo[0-5] credit stats: sent = (%d,%d,%d,%d,%d,%d), " ++ "back = (%d,%d,%d,%d,%d,%d)\n", ++ wlfc->stats.fifo_credits_sent[0], ++ wlfc->stats.fifo_credits_sent[1], ++ wlfc->stats.fifo_credits_sent[2], ++ wlfc->stats.fifo_credits_sent[3], ++ wlfc->stats.fifo_credits_sent[4], ++ wlfc->stats.fifo_credits_sent[5], ++ ++ wlfc->stats.fifo_credits_back[0], ++ wlfc->stats.fifo_credits_back[1], ++ wlfc->stats.fifo_credits_back[2], ++ wlfc->stats.fifo_credits_back[3], ++ wlfc->stats.fifo_credits_back[4], ++ wlfc->stats.fifo_credits_back[5]); ++ { ++ uint32 fifo_cr_sent = 0; ++ uint32 fifo_cr_acked = 0; ++ uint32 request_cr_sent = 0; ++ uint32 request_cr_ack = 0; ++ uint32 bc_mc_cr_ack = 0; ++ ++ for (i = 0; i < sizeof(wlfc->stats.fifo_credits_sent)/sizeof(uint32); i++) { ++ fifo_cr_sent += wlfc->stats.fifo_credits_sent[i]; ++ } ++ ++ for (i = 0; i < sizeof(wlfc->stats.fifo_credits_back)/sizeof(uint32); i++) { ++ fifo_cr_acked += wlfc->stats.fifo_credits_back[i]; ++ } ++ ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (wlfc->destination_entries.nodes[i].occupied) { ++ request_cr_sent += ++ wlfc->destination_entries.nodes[i].dstncredit_sent_packets; ++ } ++ } ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ if (wlfc->destination_entries.interfaces[i].occupied) { ++ request_cr_sent += ++ wlfc->destination_entries.interfaces[i].dstncredit_sent_packets; ++ } ++ } ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (wlfc->destination_entries.nodes[i].occupied) { ++ request_cr_ack += ++ wlfc->destination_entries.nodes[i].dstncredit_acks; ++ } ++ } ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ if (wlfc->destination_entries.interfaces[i].occupied) { ++ request_cr_ack += ++ wlfc->destination_entries.interfaces[i].dstncredit_acks; ++ } ++ } ++ bcm_bprintf(strbuf, "wlfc- (sent, status) => pq(%d,%d), vq(%d,%d)," ++ "other:%d, bc_mc:%d, signal-only, (sent,freed): (%d,%d)", ++ fifo_cr_sent, fifo_cr_acked, ++ request_cr_sent, request_cr_ack, ++ wlfc->destination_entries.other.dstncredit_acks, ++ bc_mc_cr_ack, ++ wlfc->stats.signal_only_pkts_sent, wlfc->stats.signal_only_pkts_freed); ++ } ++#endif /* PROP_TXSTATUS_DEBUG */ ++ bcm_bprintf(strbuf, "\n"); ++ bcm_bprintf(strbuf, "wlfc- pkt((in,2bus,txstats,hdrpull),(dropped,hdr_only,wlc_tossed)" ++ "(freed,free_err,rollback)) = " ++ "((%d,%d,%d,%d),(%d,%d,%d),(%d,%d,%d))\n", ++ wlfc->stats.pktin, ++ wlfc->stats.pkt2bus, ++ wlfc->stats.txstatus_in, ++ wlfc->stats.dhd_hdrpulls, ++ ++ wlfc->stats.pktdropped, ++ wlfc->stats.wlfc_header_only_pkt, ++ wlfc->stats.wlc_tossed_pkts, ++ ++ wlfc->stats.pkt_freed, ++ wlfc->stats.pkt_free_err, wlfc->stats.rollback); ++ ++ bcm_bprintf(strbuf, "wlfc- suppress((d11,wlc,err),enq(d11,wl,hq,mac?),retx(d11,wlc,hq)) = " ++ "((%d,%d,%d),(%d,%d,%d,%d),(%d,%d,%d))\n", ++ ++ wlfc->stats.d11_suppress, ++ wlfc->stats.wl_suppress, ++ wlfc->stats.bad_suppress, ++ ++ wlfc->stats.psq_d11sup_enq, ++ wlfc->stats.psq_wlsup_enq, ++ wlfc->stats.psq_hostq_enq, ++ wlfc->stats.mac_handle_notfound, ++ ++ wlfc->stats.psq_d11sup_retx, ++ wlfc->stats.psq_wlsup_retx, ++ wlfc->stats.psq_hostq_retx); ++ return; ++} ++ ++/* Create a place to store all packet pointers submitted to the firmware until ++ a status comes back, suppress or otherwise. ++ ++ hang-er: noun, a contrivance on which things are hung, as a hook. ++*/ ++static void* ++dhd_wlfc_hanger_create(osl_t *osh, int max_items) ++{ ++ int i; ++ wlfc_hanger_t* hanger; ++ ++ /* allow only up to a specific size for now */ ++ ASSERT(max_items == WLFC_HANGER_MAXITEMS); ++ ++ if ((hanger = (wlfc_hanger_t*)MALLOC(osh, WLFC_HANGER_SIZE(max_items))) == NULL) ++ return NULL; ++ ++ memset(hanger, 0, WLFC_HANGER_SIZE(max_items)); ++ hanger->max_items = max_items; ++ ++ for (i = 0; i < hanger->max_items; i++) { ++ hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } ++ return hanger; ++} ++ ++static int ++dhd_wlfc_hanger_delete(osl_t *osh, void* hanger) ++{ ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ if (h) { ++ MFREE(osh, h, WLFC_HANGER_SIZE(h->max_items)); ++ return BCME_OK; ++ } ++ return BCME_BADARG; ++} ++ ++static uint16 ++dhd_wlfc_hanger_get_free_slot(void* hanger) ++{ ++ uint32 i; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ if (h) { ++ for (i = (h->slot_pos + 1); i != h->slot_pos;) { ++ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) { ++ h->slot_pos = i; ++ return (uint16)i; ++ } ++ (i == h->max_items)? i = 0 : i++; ++ } ++ h->failed_slotfind++; ++ } ++ return WLFC_HANGER_MAXITEMS; ++} ++ ++static int ++dhd_wlfc_hanger_get_genbit(void* hanger, void* pkt, uint32 slot_id, int* gen) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ *gen = 0xff; ++ ++ /* this packet was not pushed at the time it went to the firmware */ ++ if (slot_id == WLFC_HANGER_MAXITEMS) ++ return BCME_NOTFOUND; ++ ++ if (h) { ++ if ((h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) || ++ (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { ++ *gen = h->items[slot_id].gen; ++ } ++ else { ++ rc = BCME_NOTFOUND; ++ } ++ } ++ else ++ rc = BCME_BADARG; ++ return rc; ++} ++ ++static int ++dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ if (h && (slot_id < WLFC_HANGER_MAXITEMS)) { ++ if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_FREE) { ++ h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE; ++ h->items[slot_id].pkt = pkt; ++ h->items[slot_id].identifier = slot_id; ++ h->pushed++; ++ } ++ else { ++ h->failed_to_push++; ++ rc = BCME_NOTFOUND; ++ } ++ } ++ else ++ rc = BCME_BADARG; ++ return rc; ++} ++ ++static int ++dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, int remove_from_hanger) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ /* this packet was not pushed at the time it went to the firmware */ ++ if (slot_id == WLFC_HANGER_MAXITEMS) ++ return BCME_NOTFOUND; ++ ++ if (h) { ++ if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_FREE) { ++ *pktout = h->items[slot_id].pkt; ++ if (remove_from_hanger) { ++ h->items[slot_id].state = ++ WLFC_HANGER_ITEM_STATE_FREE; ++ h->items[slot_id].pkt = NULL; ++ h->items[slot_id].identifier = 0; ++ h->items[slot_id].gen = 0xff; ++ h->popped++; ++ } ++ } ++ else { ++ h->failed_to_pop++; ++ rc = BCME_NOTFOUND; ++ } ++ } ++ else ++ rc = BCME_BADARG; ++ return rc; ++} ++ ++static int ++dhd_wlfc_hanger_mark_suppressed(void* hanger, uint32 slot_id, uint8 gen) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ /* this packet was not pushed at the time it went to the firmware */ ++ if (slot_id == WLFC_HANGER_MAXITEMS) ++ return BCME_NOTFOUND; ++ if (h) { ++ h->items[slot_id].gen = gen; ++ if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) { ++ h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED; ++ } ++ else ++ rc = BCME_BADARG; ++ } ++ else ++ rc = BCME_BADARG; ++ ++ return rc; ++} ++ ++static int ++_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void* p, bool tim_signal, ++ uint8 tim_bmp, uint8 mac_handle, uint32 htodtag) ++{ ++ uint32 wl_pktinfo = 0; ++ uint8* wlh; ++ uint8 dataOffset; ++ uint8 fillers; ++ uint8 tim_signal_len = 0; ++ ++ struct bdc_header *h; ++ ++ if (tim_signal) { ++ tim_signal_len = 1 + 1 + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; ++ } ++ ++ /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */ ++ dataOffset = WLFC_CTL_VALUE_LEN_PKTTAG + 2 + tim_signal_len; ++ fillers = ROUNDUP(dataOffset, 4) - dataOffset; ++ dataOffset += fillers; ++ ++ PKTPUSH(ctx->osh, p, dataOffset); ++ wlh = (uint8*) PKTDATA(ctx->osh, p); ++ ++ wl_pktinfo = htol32(htodtag); ++ ++ wlh[0] = WLFC_CTL_TYPE_PKTTAG; ++ wlh[1] = WLFC_CTL_VALUE_LEN_PKTTAG; ++ memcpy(&wlh[2], &wl_pktinfo, sizeof(uint32)); ++ ++ if (tim_signal_len) { ++ wlh[dataOffset - fillers - tim_signal_len ] = ++ WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP; ++ wlh[dataOffset - fillers - tim_signal_len + 1] = ++ WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; ++ wlh[dataOffset - fillers - tim_signal_len + 2] = mac_handle; ++ wlh[dataOffset - fillers - tim_signal_len + 3] = tim_bmp; ++ } ++ if (fillers) ++ memset(&wlh[dataOffset - fillers], WLFC_CTL_TYPE_FILLER, fillers); ++ ++ PKTPUSH(ctx->osh, p, BDC_HEADER_LEN); ++ h = (struct bdc_header *)PKTDATA(ctx->osh, p); ++ h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); ++ if (PKTSUMNEEDED(p)) ++ h->flags |= BDC_FLAG_SUM_NEEDED; ++ ++ ++ h->priority = (PKTPRIO(p) & BDC_PRIORITY_MASK); ++ h->flags2 = 0; ++ h->dataOffset = dataOffset >> 2; ++ BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p))); ++ return BCME_OK; ++} ++ ++static int ++_dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf) ++{ ++ struct bdc_header *h; ++ ++ if (PKTLEN(ctx->osh, pktbuf) < BDC_HEADER_LEN) { ++ AP6211_DEBUG("%s: rx data too short (%d < %d)\n", __FUNCTION__, ++ PKTLEN(ctx->osh, pktbuf), BDC_HEADER_LEN); ++ return BCME_ERROR; ++ } ++ h = (struct bdc_header *)PKTDATA(ctx->osh, pktbuf); ++ ++ /* pull BDC header */ ++ PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN); ++ ++ if (PKTLEN(ctx->osh, pktbuf) < (h->dataOffset << 2)) { ++ AP6211_DEBUG("%s: rx data too short (%d < %d)\n", __FUNCTION__, ++ PKTLEN(ctx->osh, pktbuf), (h->dataOffset << 2)); ++ return BCME_ERROR; ++ } ++ /* pull wl-header */ ++ PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2)); ++ return BCME_OK; ++} ++ ++static wlfc_mac_descriptor_t* ++_dhd_wlfc_find_table_entry(athost_wl_status_info_t* ctx, void* p) ++{ ++ int i; ++ wlfc_mac_descriptor_t* table = ctx->destination_entries.nodes; ++ uint8 ifid = DHD_PKTTAG_IF(PKTTAG(p)); ++ uint8* dstn = DHD_PKTTAG_DSTN(PKTTAG(p)); ++ ++ if (((ctx->destination_entries.interfaces[ifid].iftype == WLC_E_IF_ROLE_STA) || ++ ETHER_ISMULTI(dstn) || ++ (ctx->destination_entries.interfaces[ifid].iftype == WLC_E_IF_ROLE_P2P_CLIENT)) && ++ (ctx->destination_entries.interfaces[ifid].occupied)) { ++ return &ctx->destination_entries.interfaces[ifid]; ++ } ++ ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (table[i].occupied) { ++ if (table[i].interface_id == ifid) { ++ if (!memcmp(table[i].ea, dstn, ETHER_ADDR_LEN)) ++ return &table[i]; ++ } ++ } ++ } ++ return &ctx->destination_entries.other; ++} ++ ++static int ++_dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, ++ void* p, ewlfc_packet_state_t pkt_type, uint32 hslot) ++{ ++ /* ++ put the packet back to the head of queue ++ ++ - a packet from send-q will need to go back to send-q and not delay-q ++ since that will change the order of packets. ++ - suppressed packet goes back to suppress sub-queue ++ - pull out the header, if new or delayed packet ++ ++ Note: hslot is used only when header removal is done. ++ */ ++ wlfc_mac_descriptor_t* entry; ++ void* pktout; ++ int rc = BCME_OK; ++ int prec; ++ ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ prec = DHD_PKTTAG_FIFO(PKTTAG(p)); ++ if (entry != NULL) { ++ if (pkt_type == eWLFC_PKTTYPE_SUPPRESSED) { ++ /* wl-header is saved for suppressed packets */ ++ if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, ((prec << 1) + 1), p) == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ rc = BCME_ERROR; ++ } ++ } ++ else { ++ /* remove header first */ ++ rc = _dhd_wlfc_pullheader(ctx, p); ++ if (rc != BCME_OK) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ /* free the hanger slot */ ++ dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); ++ PKTFREE(ctx->osh, p, TRUE); ++ rc = BCME_ERROR; ++ return rc; ++ } ++ ++ if (pkt_type == eWLFC_PKTTYPE_DELAYED) { ++ /* delay-q packets are going to delay-q */ ++ if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, (prec << 1), p) == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ rc = BCME_ERROR; ++ } ++ } ++ else { ++ /* these are going to SENDQ */ ++ if (WLFC_PKTQ_PENQ_HEAD(&ctx->SENDQ, prec, p) == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ rc = BCME_ERROR; ++ } ++ } ++ /* free the hanger slot */ ++ dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); ++ ++ /* decrement sequence count */ ++ WLFC_DECR_SEQCOUNT(entry, prec); ++ } ++ /* ++ if this packet did not count against FIFO credit, it must have ++ taken a requested_credit from the firmware (for pspoll etc.) ++ */ ++ if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { ++ entry->requested_credit++; ++ } ++ } ++ else { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ rc = BCME_ERROR; ++ } ++ if (rc != BCME_OK) ++ ctx->stats.rollback_failed++; ++ else ++ ctx->stats.rollback++; ++ ++ return rc; ++} ++ ++static void ++_dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint8 if_id) ++{ ++ if ((pq->len <= WLFC_FLOWCONTROL_LOWATER) && (ctx->hostif_flow_state[if_id] == ON)) { ++ /* start traffic */ ++ ctx->hostif_flow_state[if_id] = OFF; ++ /* ++ AP6211_DEBUG("qlen:%02d, if:%02d, ->OFF, start traffic %s()\n", ++ pq->len, if_id, __FUNCTION__); ++ */ ++ AP6211_DEBUG("F"); ++ dhd_txflowcontrol(ctx->dhdp, if_id, OFF); ++ ctx->toggle_host_if = 0; ++ } ++ if ((pq->len >= WLFC_FLOWCONTROL_HIWATER) && (ctx->hostif_flow_state[if_id] == OFF)) { ++ /* stop traffic */ ++ ctx->hostif_flow_state[if_id] = ON; ++ /* ++ AP6211_DEBUG("qlen:%02d, if:%02d, ->ON, stop traffic %s()\n", ++ pq->len, if_id, __FUNCTION__); ++ */ ++ AP6211_DEBUG("N"); ++ dhd_txflowcontrol(ctx->dhdp, if_id, ON); ++ ctx->host_ifidx = if_id; ++ ctx->toggle_host_if = 1; ++ } ++ return; ++} ++ ++static int ++_dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, ++ uint8 ta_bmp) ++{ ++ int rc = BCME_OK; ++ void* p = NULL; ++ int dummylen = ((dhd_pub_t *)ctx->dhdp)->hdrlen+ 12; ++ ++ /* allocate a dummy packet */ ++ p = PKTGET(ctx->osh, dummylen, TRUE); ++ if (p) { ++ PKTPULL(ctx->osh, p, dummylen); ++ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0); ++ _dhd_wlfc_pushheader(ctx, p, TRUE, ta_bmp, entry->mac_handle, 0); ++ DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1); ++#ifdef PROP_TXSTATUS_DEBUG ++ ctx->stats.signal_only_pkts_sent++; ++#endif ++ rc = dhd_bus_txdata(((dhd_pub_t *)ctx->dhdp)->bus, p, FALSE); ++ if (rc != BCME_OK) { ++ PKTFREE(ctx->osh, p, TRUE); ++ } ++ } ++ else { ++ AP6211_ERR("%s: couldn't allocate new %d-byte packet\n", ++ __FUNCTION__, dummylen); ++ rc = BCME_NOMEM; ++ } ++ return rc; ++} ++ ++/* Return TRUE if traffic availability changed */ ++static bool ++_dhd_wlfc_traffic_pending_check(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, ++ int prec) ++{ ++ bool rc = FALSE; ++ ++ if (entry->state == WLFC_STATE_CLOSE) { ++ if ((pktq_plen(&entry->psq, (prec << 1)) == 0) && ++ (pktq_plen(&entry->psq, ((prec << 1) + 1)) == 0)) { ++ ++ if (entry->traffic_pending_bmp & NBITVAL(prec)) { ++ rc = TRUE; ++ entry->traffic_pending_bmp = ++ entry->traffic_pending_bmp & ~ NBITVAL(prec); ++ } ++ } ++ else { ++ if (!(entry->traffic_pending_bmp & NBITVAL(prec))) { ++ rc = TRUE; ++ entry->traffic_pending_bmp = ++ entry->traffic_pending_bmp | NBITVAL(prec); ++ } ++ } ++ } ++ if (rc) { ++ /* request a TIM update to firmware at the next piggyback opportunity */ ++ if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp) { ++ entry->send_tim_signal = 1; ++ _dhd_wlfc_send_signalonly_packet(ctx, entry, entry->traffic_pending_bmp); ++ entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; ++ entry->send_tim_signal = 0; ++ } ++ else { ++ rc = FALSE; ++ } ++ } ++ return rc; ++} ++ ++static int ++_dhd_wlfc_enque_suppressed(athost_wl_status_info_t* ctx, int prec, void* p) ++{ ++ wlfc_mac_descriptor_t* entry; ++ ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ if (entry == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_NOTFOUND; ++ } ++ /* ++ - suppressed packets go to sub_queue[2*prec + 1] AND ++ - delayed packets go to sub_queue[2*prec + 0] to ensure ++ order of delivery. ++ */ ++ if (WLFC_PKTQ_PENQ(&entry->psq, ((prec << 1) + 1), p) == NULL) { ++ ctx->stats.delayq_full_error++; ++ /* AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); */ ++ AP6211_DEBUG("s"); ++ return BCME_ERROR; ++ } ++ /* A packet has been pushed, update traffic availability bitmap, if applicable */ ++ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); ++ _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p))); ++ return BCME_OK; ++} ++ ++static int ++_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, ++ wlfc_mac_descriptor_t* entry, void* p, int header_needed, uint32* slot) ++{ ++ int rc = BCME_OK; ++ int hslot = WLFC_HANGER_MAXITEMS; ++ bool send_tim_update = FALSE; ++ uint32 htod = 0; ++ uint8 free_ctr; ++ ++ *slot = hslot; ++ ++ if (entry == NULL) { ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ } ++ ++ if (entry == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_ERROR; ++ } ++ if (entry->send_tim_signal) { ++ send_tim_update = TRUE; ++ entry->send_tim_signal = 0; ++ entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; ++ } ++ if (header_needed) { ++ hslot = dhd_wlfc_hanger_get_free_slot(ctx->hanger); ++ free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); ++ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); ++ WLFC_PKTFLAG_SET_GENERATION(htod, entry->generation); ++ entry->transit_count++; ++ } ++ else { ++ hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ } ++ WLFC_PKTID_HSLOT_SET(htod, hslot); ++ WLFC_PKTID_FREERUNCTR_SET(htod, free_ctr); ++ DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1); ++ WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); ++ WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p))); ++ ++ if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { ++ /* ++ Indicate that this packet is being sent in response to an ++ explicit request from the firmware side. ++ */ ++ WLFC_PKTFLAG_SET_PKTREQUESTED(htod); ++ } ++ else { ++ WLFC_PKTFLAG_CLR_PKTREQUESTED(htod); ++ } ++ if (header_needed) { ++ rc = _dhd_wlfc_pushheader(ctx, p, send_tim_update, ++ entry->traffic_lastreported_bmp, entry->mac_handle, htod); ++ if (rc == BCME_OK) { ++ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); ++ /* ++ a new header was created for this packet. ++ push to hanger slot and scrub q. Since bus ++ send succeeded, increment seq number as well. ++ */ ++ rc = dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot); ++ if (rc == BCME_OK) { ++ /* increment free running sequence count */ ++ WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); ++#ifdef PROP_TXSTATUS_DEBUG ++ ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].push_time = ++ OSL_SYSUPTIME(); ++#endif ++ } ++ else { ++ AP6211_DEBUG("%s() hanger_pushpkt() failed, rc: %d\n", ++ __FUNCTION__, rc); ++ } ++ } ++ } ++ else { ++ int gen; ++ ++ /* remove old header */ ++ rc = _dhd_wlfc_pullheader(ctx, p); ++ if (rc == BCME_OK) { ++ hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ dhd_wlfc_hanger_get_genbit(ctx->hanger, p, hslot, &gen); ++ ++ WLFC_PKTFLAG_SET_GENERATION(htod, gen); ++ free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ /* push new header */ ++ _dhd_wlfc_pushheader(ctx, p, send_tim_update, ++ entry->traffic_lastreported_bmp, entry->mac_handle, htod); ++ } ++ } ++ *slot = hslot; ++ return rc; ++} ++ ++static int ++_dhd_wlfc_is_destination_closed(athost_wl_status_info_t* ctx, ++ wlfc_mac_descriptor_t* entry, int prec) ++{ ++ if (ctx->destination_entries.interfaces[entry->interface_id].iftype == ++ WLC_E_IF_ROLE_P2P_GO) { ++ /* - destination interface is of type p2p GO. ++ For a p2pGO interface, if the destination is OPEN but the interface is ++ CLOSEd, do not send traffic. But if the dstn is CLOSEd while there is ++ destination-specific-credit left send packets. This is because the ++ firmware storing the destination-specific-requested packet in queue. ++ */ ++ if ((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && ++ (entry->requested_packet == 0)) ++ return 1; ++ } ++ /* AP, p2p_go -> unicast desc entry, STA/p2p_cl -> interface desc. entry */ ++ if (((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && ++ (entry->requested_packet == 0)) || ++ (!(entry->ac_bitmap & (1 << prec)))) ++ return 1; ++ ++ return 0; ++} ++ ++static void* ++_dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, ++ int prec, uint8* ac_credit_spent, uint8* needs_hdr, wlfc_mac_descriptor_t** entry_out) ++{ ++ wlfc_mac_descriptor_t* entry; ++ wlfc_mac_descriptor_t* table; ++ uint8 token_pos; ++ int total_entries; ++ void* p = NULL; ++ int pout; ++ int i; ++ ++ *entry_out = NULL; ++ token_pos = ctx->token_pos[prec]; ++ /* most cases a packet will count against FIFO credit */ ++ *ac_credit_spent = 1; ++ *needs_hdr = 1; ++ ++ /* search all entries, include nodes as well as interfaces */ ++ table = (wlfc_mac_descriptor_t*)&ctx->destination_entries; ++ total_entries = sizeof(ctx->destination_entries)/sizeof(wlfc_mac_descriptor_t); ++ ++ for (i = 0; i < total_entries; i++) { ++ entry = &table[(token_pos + i) % total_entries]; ++ if (entry->occupied) { ++ if (!_dhd_wlfc_is_destination_closed(ctx, entry, prec)) { ++ p = pktq_mdeq(&entry->psq, ++ /* higher precedence will be picked up first, ++ * i.e. suppressed packets before delayed ones ++ */ ++ NBITVAL((prec << 1) + 1), &pout); ++ *needs_hdr = 0; ++ ++ if (p == NULL) { ++ if (entry->suppressed == TRUE) { ++ if ((entry->suppr_transit_count <= ++ entry->suppress_count)) { ++ entry->suppressed = FALSE; ++ } else { ++ return NULL; ++ } ++ } ++ /* De-Q from delay Q */ ++ p = pktq_mdeq(&entry->psq, ++ NBITVAL((prec << 1)), ++ &pout); ++ *needs_hdr = 1; ++ } ++ ++ if (p != NULL) { ++ /* did the packet come from suppress sub-queue? */ ++ if (entry->requested_credit > 0) { ++ entry->requested_credit--; ++#ifdef PROP_TXSTATUS_DEBUG ++ entry->dstncredit_sent_packets++; ++#endif ++ /* ++ if the packet was pulled out while destination is in ++ closed state but had a non-zero packets requested, ++ then this should not count against the FIFO credit. ++ That is due to the fact that the firmware will ++ most likely hold onto this packet until a suitable ++ time later to push it to the appropriate AC FIFO. ++ */ ++ if (entry->state == WLFC_STATE_CLOSE) ++ *ac_credit_spent = 0; ++ } ++ else if (entry->requested_packet > 0) { ++ entry->requested_packet--; ++ DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p)); ++ if (entry->state == WLFC_STATE_CLOSE) ++ *ac_credit_spent = 0; ++ } ++ /* move token to ensure fair round-robin */ ++ ctx->token_pos[prec] = ++ (token_pos + i + 1) % total_entries; ++ *entry_out = entry; ++ _dhd_wlfc_flow_control_check(ctx, &entry->psq, ++ DHD_PKTTAG_IF(PKTTAG(p))); ++ /* ++ A packet has been picked up, update traffic ++ availability bitmap, if applicable ++ */ ++ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); ++ return p; ++ } ++ } ++ } ++ } ++ return NULL; ++} ++ ++static void* ++_dhd_wlfc_deque_sendq(athost_wl_status_info_t* ctx, int prec) ++{ ++ wlfc_mac_descriptor_t* entry; ++ void* p; ++ ++ ++ p = pktq_pdeq(&ctx->SENDQ, prec); ++ if (p != NULL) { ++ if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(p)))) ++ /* bc/mc packets do not have a delay queue */ ++ return p; ++ ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ ++ if (entry == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return p; ++ } ++ ++ while ((p != NULL)) { ++ /* ++ - suppressed packets go to sub_queue[2*prec + 1] AND ++ - delayed packets go to sub_queue[2*prec + 0] to ensure ++ order of delivery. ++ */ ++ if (WLFC_PKTQ_PENQ(&entry->psq, (prec << 1), p) == NULL) { ++ AP6211_DEBUG("D"); ++ /* dhd_txcomplete(ctx->dhdp, p, FALSE); */ ++ PKTFREE(ctx->osh, p, TRUE); ++ ctx->stats.delayq_full_error++; ++ } ++ /* ++ A packet has been pushed, update traffic availability bitmap, ++ if applicable ++ */ ++ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); ++ ++ p = pktq_pdeq(&ctx->SENDQ, prec); ++ if (p == NULL) ++ break; ++ ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ ++ if ((entry == NULL) || (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(p))))) { ++ return p; ++ } ++ } ++ } ++ return p; ++} ++ ++static int ++_dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, ++ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) ++{ ++ int rc = BCME_OK; ++ ++ if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { ++ entry->occupied = 1; ++ entry->state = WLFC_STATE_OPEN; ++ entry->requested_credit = 0; ++ entry->interface_id = ifid; ++ entry->iftype = iftype; ++ entry->ac_bitmap = 0xff; /* update this when handling APSD */ ++ /* for an interface entry we may not care about the MAC address */ ++ if (ea != NULL) ++ memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); ++ pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN); ++ } ++ else if (action == eWLFC_MAC_ENTRY_ACTION_UPDATE) { ++ entry->occupied = 1; ++ entry->state = WLFC_STATE_OPEN; ++ entry->requested_credit = 0; ++ entry->interface_id = ifid; ++ entry->iftype = iftype; ++ entry->ac_bitmap = 0xff; /* update this when handling APSD */ ++ /* for an interface entry we may not care about the MAC address */ ++ if (ea != NULL) ++ memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); ++ } ++ else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) { ++ entry->occupied = 0; ++ entry->state = WLFC_STATE_CLOSE; ++ entry->requested_credit = 0; ++ /* enable after packets are queued-deqeued properly. ++ pktq_flush(dhd->osh, &entry->psq, FALSE, NULL, 0); ++ */ ++ } ++ return rc; ++} ++ ++int ++_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, uint8 available_credit_map, int borrower_ac) ++{ ++ int lender_ac; ++ int rc = BCME_ERROR; ++ ++ if (ctx == NULL || available_credit_map == 0) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_BADARG; ++ } ++ ++ /* Borrow from lowest priority available AC (including BC/MC credits) */ ++ for (lender_ac = 0; lender_ac <= AC_COUNT; lender_ac++) { ++ if ((available_credit_map && (1 << lender_ac)) && ++ (ctx->FIFO_credit[lender_ac] > 0)) { ++ ctx->credits_borrowed[borrower_ac][lender_ac]++; ++ ctx->FIFO_credit[lender_ac]--; ++ rc = BCME_OK; ++ break; ++ } ++ } ++ ++ return rc; ++} ++ ++int ++dhd_wlfc_interface_entry_update(void* state, ++ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) ++{ ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ wlfc_mac_descriptor_t* entry; ++ ++ if (ifid >= WLFC_MAX_IFNUM) ++ return BCME_BADARG; ++ ++ entry = &ctx->destination_entries.interfaces[ifid]; ++ return _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea); ++} ++ ++int ++dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits) ++{ ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ ++ /* update the AC FIFO credit map */ ++ ctx->FIFO_credit[0] = credits[0]; ++ ctx->FIFO_credit[1] = credits[1]; ++ ctx->FIFO_credit[2] = credits[2]; ++ ctx->FIFO_credit[3] = credits[3]; ++ /* credit for bc/mc packets */ ++ ctx->FIFO_credit[4] = credits[4]; ++ /* credit for ATIM FIFO is not used yet. */ ++ ctx->FIFO_credit[5] = 0; ++ return BCME_OK; ++} ++ ++int ++dhd_wlfc_enque_sendq(void* state, int prec, void* p) ++{ ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ ++ if ((state == NULL) || ++ /* prec = AC_COUNT is used for bc/mc queue */ ++ (prec > AC_COUNT) || ++ (p == NULL)) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_BADARG; ++ } ++ if (FALSE == dhd_prec_enq(ctx->dhdp, &ctx->SENDQ, p, prec)) { ++ ctx->stats.sendq_full_error++; ++ /* ++ AP6211_DEBUG("Error: %s():%d, qlen:%d\n", ++ __FUNCTION__, __LINE__, ctx->SENDQ.len); ++ */ ++ WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, prec); ++ AP6211_DEBUG("Q"); ++ PKTFREE(ctx->osh, p, TRUE); ++ return BCME_ERROR; ++ } ++ ctx->stats.pktin++; ++ /* _dhd_wlfc_flow_control_check(ctx, &ctx->SENDQ, DHD_PKTTAG_IF(PKTTAG(p))); */ ++ return BCME_OK; ++} ++ ++int ++_dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, ++ dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx) ++{ ++ uint32 hslot; ++ int rc; ++ ++ /* ++ if ac_fifo_credit_spent = 0 ++ ++ This packet will not count against the FIFO credit. ++ To ensure the txstatus corresponding to this packet ++ does not provide an implied credit (default behavior) ++ mark the packet accordingly. ++ ++ if ac_fifo_credit_spent = 1 ++ ++ This is a normal packet and it counts against the FIFO ++ credit count. ++ */ ++ DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent); ++ rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, commit_info->p, ++ commit_info->needs_hdr, &hslot); ++ ++ if (rc == BCME_OK) ++ rc = fcommit(commit_ctx, commit_info->p, TRUE); ++ else ++ ctx->stats.generic_error++; ++ ++ if (rc == BCME_OK) { ++ ctx->stats.pkt2bus++; ++ if (commit_info->ac_fifo_credit_spent) { ++ ctx->stats.sendq_pkts[ac]++; ++ WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac); ++ } ++ } else if (rc == BCME_NORESOURCE) ++ rc = BCME_ERROR; ++ else { ++ /* ++ bus commit has failed, rollback. ++ - remove wl-header for a delayed packet ++ - save wl-header header for suppressed packets ++ */ ++ rc = _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p, ++ (commit_info->pkt_type), hslot); ++ if (rc != BCME_OK) ++ ctx->stats.rollback_failed++; ++ ++ rc = BCME_ERROR; ++ } ++ ++ return rc; ++} ++ ++int ++dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx) ++{ ++ int ac; ++ int credit; ++ int rc; ++ dhd_wlfc_commit_info_t commit_info; ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ int credit_count = 0; ++ int bus_retry_count = 0; ++ uint8 ac_available = 0; /* Bitmask for 4 ACs + BC/MC */ ++ ++ if ((state == NULL) || ++ (fcommit == NULL)) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_BADARG; ++ } ++ ++ memset(&commit_info, 0, sizeof(commit_info)); ++ ++ /* ++ Commit packets for regular AC traffic. Higher priority first. ++ First, use up FIFO credits available to each AC. Based on distribution ++ and credits left, borrow from other ACs as applicable ++ ++ -NOTE: ++ If the bus between the host and firmware is overwhelmed by the ++ traffic from host, it is possible that higher priority traffic ++ starves the lower priority queue. If that occurs often, we may ++ have to employ weighted round-robin or ucode scheme to avoid ++ low priority packet starvation. ++ */ ++ ++ for (ac = AC_COUNT; ac >= 0; ac--) { ++ ++ int initial_credit_count = ctx->FIFO_credit[ac]; ++ ++ /* packets from SENDQ are fresh and they'd need header and have no MAC entry */ ++ commit_info.needs_hdr = 1; ++ commit_info.mac_entry = NULL; ++ commit_info.pkt_type = eWLFC_PKTTYPE_NEW; ++ ++ do { ++ commit_info.p = _dhd_wlfc_deque_sendq(ctx, ac); ++ if (commit_info.p == NULL) ++ break; ++ else if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(commit_info.p)))) { ++ ASSERT(ac == AC_COUNT); ++ ++ if (ctx->FIFO_credit[ac]) { ++ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, ++ fcommit, commit_ctx); ++ ++ /* Bus commits may fail (e.g. flow control); abort after retries */ ++ if (rc == BCME_OK) { ++ if (commit_info.ac_fifo_credit_spent) { ++ (void) _dhd_wlfc_borrow_credit(ctx, ++ ac_available, ac); ++ credit_count--; ++ } ++ } else { ++ bus_retry_count++; ++ if (bus_retry_count >= BUS_RETRIES) { ++ AP6211_ERR(" %s: bus error\n", ++ __FUNCTION__); ++ return rc; ++ } ++ } ++ } ++ } ++ ++ } while (commit_info.p); ++ ++ for (credit = 0; credit < ctx->FIFO_credit[ac];) { ++ commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, ++ &(commit_info.ac_fifo_credit_spent), ++ &(commit_info.needs_hdr), ++ &(commit_info.mac_entry)); ++ ++ if (commit_info.p == NULL) ++ break; ++ ++ commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : ++ eWLFC_PKTTYPE_SUPPRESSED; ++ ++ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, ++ fcommit, commit_ctx); ++ ++ /* Bus commits may fail (e.g. flow control); abort after retries */ ++ if (rc == BCME_OK) { ++ if (commit_info.ac_fifo_credit_spent) { ++ credit++; ++ } ++ } ++ else { ++ bus_retry_count++; ++ if (bus_retry_count >= BUS_RETRIES) { ++ AP6211_ERR("dhd_wlfc_commit_packets(): bus error\n"); ++ ctx->FIFO_credit[ac] -= credit; ++ return rc; ++ } ++ } ++ } ++ ++ ctx->FIFO_credit[ac] -= credit; ++ ++ ++ /* If no credits were used, the queue is idle and can be re-used ++ Note that resv credits cannot be borrowed ++ */ ++ if (initial_credit_count == ctx->FIFO_credit[ac]) { ++ ac_available |= (1 << ac); ++ credit_count += ctx->FIFO_credit[ac]; ++ } ++ } ++ ++ /* We borrow only for AC_BE and only if no other traffic seen for DEFER_PERIOD ++ ++ Note that (ac_available & WLFC_AC_BE_TRAFFIC_ONLY) is done to: ++ a) ignore BC/MC for deferring borrow ++ b) ignore AC_BE being available along with other ACs ++ (this should happen only for pure BC/MC traffic) ++ ++ i.e. AC_VI, AC_VO, AC_BK all MUST be available (i.e. no traffic) and ++ we do not care if AC_BE and BC/MC are available or not ++ */ ++ if ((ac_available & WLFC_AC_BE_TRAFFIC_ONLY) == WLFC_AC_BE_TRAFFIC_ONLY) { ++ ++ if (ctx->allow_credit_borrow) { ++ ac = 1; /* Set ac to AC_BE and borrow credits */ ++ } ++ else { ++ int delta; ++ int curr_t = OSL_SYSUPTIME(); ++ ++ if (curr_t > ctx->borrow_defer_timestamp) ++ delta = curr_t - ctx->borrow_defer_timestamp; ++ else ++ delta = 0xffffffff + curr_t - ctx->borrow_defer_timestamp; ++ ++ if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) { ++ /* Reset borrow but defer to next iteration (defensive borrowing) */ ++ ctx->allow_credit_borrow = TRUE; ++ ctx->borrow_defer_timestamp = 0; ++ } ++ return BCME_OK; ++ } ++ } ++ else { ++ /* If we have multiple AC traffic, turn off borrowing, mark time and bail out */ ++ ctx->allow_credit_borrow = FALSE; ++ ctx->borrow_defer_timestamp = OSL_SYSUPTIME(); ++ return BCME_OK; ++ } ++ ++ /* At this point, borrow all credits only for "ac" (which should be set above to AC_BE) ++ Generically use "ac" only in case we extend to all ACs in future ++ */ ++ for (; (credit_count > 0);) { ++ ++ commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, ++ &(commit_info.ac_fifo_credit_spent), ++ &(commit_info.needs_hdr), ++ &(commit_info.mac_entry)); ++ if (commit_info.p == NULL) ++ break; ++ ++ commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : ++ eWLFC_PKTTYPE_SUPPRESSED; ++ ++ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, ++ fcommit, commit_ctx); ++ ++ /* Bus commits may fail (e.g. flow control); abort after retries */ ++ if (rc == BCME_OK) { ++ if (commit_info.ac_fifo_credit_spent) { ++ (void) _dhd_wlfc_borrow_credit(ctx, ac_available, ac); ++ credit_count--; ++ } ++ } ++ else { ++ bus_retry_count++; ++ if (bus_retry_count >= BUS_RETRIES) { ++ AP6211_ERR("dhd_wlfc_commit_packets(): bus error\n"); ++ return rc; ++ } ++ } ++ } ++ ++ return BCME_OK; ++} ++ ++static uint8 ++dhd_wlfc_find_mac_desc_id_from_mac(dhd_pub_t *dhdp, uint8* ea) ++{ ++ wlfc_mac_descriptor_t* table = ++ ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes; ++ uint8 table_index; ++ ++ if (ea != NULL) { ++ for (table_index = 0; table_index < WLFC_MAC_DESC_TABLE_SIZE; table_index++) { ++ if ((memcmp(ea, &table[table_index].ea[0], ETHER_ADDR_LEN) == 0) && ++ table[table_index].occupied) ++ return table_index; ++ } ++ } ++ return WLFC_MAC_DESC_ID_INVALID; ++} ++ ++void ++dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success, bool wake_locked) ++{ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ void* p; ++ int fifo_id; ++ ++ if (!wake_locked) ++ dhd_os_wlfc_block(dhd); ++ ++ if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) { ++#ifdef PROP_TXSTATUS_DEBUG ++ wlfc->stats.signal_only_pkts_freed++; ++#endif ++ if (success) ++ /* is this a signal-only packet? */ ++ PKTFREE(wlfc->osh, txp, TRUE); ++ if (!wake_locked) ++ dhd_os_wlfc_unblock(dhd); ++ return; ++ } ++ if (!success) { ++ AP6211_DEBUG("At: %s():%d, bus_complete() failure for %p, htod_tag:0x%08x\n", ++ __FUNCTION__, __LINE__, txp, DHD_PKTTAG_H2DTAG(PKTTAG(txp))); ++ dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG ++ (PKTTAG(txp))), &p, 1); ++ ++ /* indicate failure and free the packet */ ++ dhd_txcomplete(dhd, txp, FALSE); ++ ++ /* return the credit, if necessary */ ++ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(txp))) { ++ int lender, credit_returned = 0; /* Note that borrower is fifo_id */ ++ ++ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(txp)); ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; lender >= 0; lender--) { ++ if (wlfc->credits_borrowed[fifo_id][lender] > 0) { ++ wlfc->FIFO_credit[lender]++; ++ wlfc->credits_borrowed[fifo_id][lender]--; ++ credit_returned = 1; ++ break; ++ } ++ } ++ ++ if (!credit_returned) { ++ wlfc->FIFO_credit[fifo_id]++; ++ } ++ } ++ ++ PKTFREE(wlfc->osh, txp, TRUE); ++ } ++ if (!wake_locked) ++ dhd_os_wlfc_unblock(dhd); ++ return; ++} ++ ++static int ++dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len) ++{ ++ uint8 status_flag; ++ uint32 status; ++ int ret; ++ int remove_from_hanger = 1; ++ void* pktbuf; ++ uint8 fifo_id; ++ uint8 count = 0; ++ uint32 status_g; ++ uint32 hslot, hcnt; ++ wlfc_mac_descriptor_t* entry = NULL; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ ++ memcpy(&status, pkt_info, sizeof(uint32)); ++ status_flag = WL_TXSTATUS_GET_FLAGS(status); ++ status_g = status & 0xff000000; ++ hslot = (status & 0x00ffff00) >> 8; ++ hcnt = status & 0xff; ++ len = pkt_info[4]; ++ ++ wlfc->stats.txstatus_in++; ++ ++ if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { ++ wlfc->stats.pkt_freed++; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { ++ wlfc->stats.d11_suppress++; ++ remove_from_hanger = 0; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { ++ wlfc->stats.wl_suppress++; ++ remove_from_hanger = 0; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { ++ wlfc->stats.wlc_tossed_pkts++; ++ } ++ while (count < len) { ++ status = (status_g << 24) | (hslot << 8) | (hcnt); ++ count++; ++ hslot++; ++ hcnt++; ++ ++ ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, ++ WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); ++ if (ret != BCME_OK) { ++ /* do something */ ++ continue; ++ } ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ ++ if (!remove_from_hanger) { ++ /* this packet was suppressed */ ++ if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { ++ entry->suppressed = TRUE; ++ entry->suppress_count = pktq_mlen(&entry->psq, ++ NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); ++ entry->suppr_transit_count = entry->transit_count; ++ } ++ entry->generation = WLFC_PKTID_GEN(status); ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ uint32 new_t = OSL_SYSUPTIME(); ++ uint32 old_t; ++ uint32 delta; ++ old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ ++ WLFC_PKTID_HSLOT_GET(status)].push_time; ++ ++ ++ wlfc->stats.latency_sample_count++; ++ if (new_t > old_t) ++ delta = new_t - old_t; ++ else ++ delta = 0xffffffff + new_t - old_t; ++ wlfc->stats.total_status_latency += delta; ++ wlfc->stats.latency_most_recent = delta; ++ ++ wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; ++ if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) ++ wlfc->stats.idx_delta = 0; ++ } ++#endif /* PROP_TXSTATUS_DEBUG */ ++ ++ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); ++ ++ /* pick up the implicit credit from this packet */ ++ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { ++ if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { ++ ++ int lender, credit_returned = 0; /* Note that borrower is fifo_id */ ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; lender >= 0; lender--) { ++ if (wlfc->credits_borrowed[fifo_id][lender] > 0) { ++ wlfc->FIFO_credit[lender]++; ++ wlfc->credits_borrowed[fifo_id][lender]--; ++ credit_returned = 1; ++ break; ++ } ++ } ++ ++ if (!credit_returned) { ++ wlfc->FIFO_credit[fifo_id]++; ++ } ++ } ++ } ++ else { ++ /* ++ if this packet did not count against FIFO credit, it must have ++ taken a requested_credit from the destination entry (for pspoll etc.) ++ */ ++ if (!entry) { ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ } ++ if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) ++ entry->requested_credit++; ++#ifdef PROP_TXSTATUS_DEBUG ++ entry->dstncredit_acks++; ++#endif ++ } ++ if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || ++ (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { ++ ++ ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); ++ if (ret != BCME_OK) { ++ /* delay q is full, drop this packet */ ++ dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), ++ &pktbuf, 1); ++ ++ /* indicate failure and free the packet */ ++ dhd_txcomplete(dhd, pktbuf, FALSE); ++ entry->transit_count--; ++ /* packet is transmitted Successfully by dongle ++ * after first suppress. ++ */ ++ if (entry->suppressed) { ++ entry->suppr_transit_count--; ++ } ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } else { ++ /* Mark suppressed to avoid a double free during wlfc cleanup */ ++ ++ dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, ++ WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); ++ entry->suppress_count++; ++ } ++ } ++ else { ++ dhd_txcomplete(dhd, pktbuf, TRUE); ++ entry->transit_count--; ++ ++ /* This packet is transmitted Successfully by dongle ++ * even after first suppress. ++ */ ++ if (entry->suppressed) { ++ entry->suppr_transit_count--; ++ } ++ /* free the packet */ ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } ++ } ++ return BCME_OK; ++} ++ ++/* Handle discard or suppress indication */ ++static int ++dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info) ++{ ++ uint8 status_flag; ++ uint32 status; ++ int ret; ++ int remove_from_hanger = 1; ++ void* pktbuf; ++ uint8 fifo_id; ++ wlfc_mac_descriptor_t* entry = NULL; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ ++ memcpy(&status, pkt_info, sizeof(uint32)); ++ status_flag = WL_TXSTATUS_GET_FLAGS(status); ++ wlfc->stats.txstatus_in++; ++ ++ if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { ++ wlfc->stats.pkt_freed++; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { ++ wlfc->stats.d11_suppress++; ++ remove_from_hanger = 0; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { ++ wlfc->stats.wl_suppress++; ++ remove_from_hanger = 0; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { ++ wlfc->stats.wlc_tossed_pkts++; ++ } ++ ++ ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, ++ WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); ++ if (ret != BCME_OK) { ++ /* do something */ ++ return ret; ++ } ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ ++ if (!remove_from_hanger) { ++ /* this packet was suppressed */ ++ if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { ++ entry->suppressed = TRUE; ++ entry->suppress_count = pktq_mlen(&entry->psq, ++ NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); ++ entry->suppr_transit_count = entry->transit_count; ++ } ++ entry->generation = WLFC_PKTID_GEN(status); ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ uint32 new_t = OSL_SYSUPTIME(); ++ uint32 old_t; ++ uint32 delta; ++ old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ ++ WLFC_PKTID_HSLOT_GET(status)].push_time; ++ ++ ++ wlfc->stats.latency_sample_count++; ++ if (new_t > old_t) ++ delta = new_t - old_t; ++ else ++ delta = 0xffffffff + new_t - old_t; ++ wlfc->stats.total_status_latency += delta; ++ wlfc->stats.latency_most_recent = delta; ++ ++ wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; ++ if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) ++ wlfc->stats.idx_delta = 0; ++ } ++#endif /* PROP_TXSTATUS_DEBUG */ ++ ++ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); ++ ++ /* pick up the implicit credit from this packet */ ++ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { ++ if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { ++ ++ int lender, credit_returned = 0; /* Note that borrower is fifo_id */ ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; lender >= 0; lender--) { ++ if (wlfc->credits_borrowed[fifo_id][lender] > 0) { ++ wlfc->FIFO_credit[lender]++; ++ wlfc->credits_borrowed[fifo_id][lender]--; ++ credit_returned = 1; ++ break; ++ } ++ } ++ ++ if (!credit_returned) { ++ wlfc->FIFO_credit[fifo_id]++; ++ } ++ } ++ } ++ else { ++ /* ++ if this packet did not count against FIFO credit, it must have ++ taken a requested_credit from the destination entry (for pspoll etc.) ++ */ ++ if (!entry) { ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ } ++ if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) ++ entry->requested_credit++; ++#ifdef PROP_TXSTATUS_DEBUG ++ entry->dstncredit_acks++; ++#endif ++ } ++ if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || ++ (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { ++ ++ ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); ++ if (ret != BCME_OK) { ++ /* delay q is full, drop this packet */ ++ dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), ++ &pktbuf, 1); ++ ++ /* indicate failure and free the packet */ ++ dhd_txcomplete(dhd, pktbuf, FALSE); ++ entry->transit_count--; ++ /* This packet is transmitted Successfully by ++ * dongle even after first suppress. ++ */ ++ if (entry->suppressed) { ++ entry->suppr_transit_count--; ++ } ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } else { ++ /* Mark suppressed to avoid a double free during wlfc cleanup */ ++ dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, ++ WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); ++ entry->suppress_count++; ++ } ++ } ++ else { ++ dhd_txcomplete(dhd, pktbuf, TRUE); ++ entry->transit_count--; ++ ++ /* This packet is transmitted Successfully by dongle even after first suppress. */ ++ if (entry->suppressed) { ++ entry->suppr_transit_count--; ++ } ++ /* free the packet */ ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) ++{ ++ int i; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ for (i = 0; i < WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK; i++) { ++#ifdef PROP_TXSTATUS_DEBUG ++ wlfc->stats.fifo_credits_back[i] += credits[i]; ++#endif ++ /* update FIFO credits */ ++ if (wlfc->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT) ++ { ++ int lender; /* Note that borrower is i */ ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) { ++ if (wlfc->credits_borrowed[i][lender] > 0) { ++ if (credits[i] >= wlfc->credits_borrowed[i][lender]) { ++ credits[i] -= wlfc->credits_borrowed[i][lender]; ++ wlfc->FIFO_credit[lender] += ++ wlfc->credits_borrowed[i][lender]; ++ wlfc->credits_borrowed[i][lender] = 0; ++ } ++ else { ++ wlfc->credits_borrowed[i][lender] -= credits[i]; ++ wlfc->FIFO_credit[lender] += credits[i]; ++ credits[i] = 0; ++ } ++ } ++ } ++ ++ /* If we have more credits left over, these must belong to the AC */ ++ if (credits[i] > 0) { ++ wlfc->FIFO_credit[i] += credits[i]; ++ } ++ } ++ } ++ ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value) ++{ ++ uint32 timestamp; ++ ++ (void)dhd; ++ ++ bcopy(&value[2], ×tamp, sizeof(uint32)); ++ AP6211_DEBUG("RXPKT: SEQ: %d, timestamp %d\n", value[1], timestamp); ++ return BCME_OK; ++} ++ ++ ++static int ++dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi) ++{ ++ (void)dhd; ++ (void)rssi; ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_mac_table_update(dhd_pub_t *dhd, uint8* value, uint8 type) ++{ ++ int rc; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ uint8 existing_index; ++ uint8 table_index; ++ uint8 ifid; ++ uint8* ea; ++ ++ AP6211_DEBUG("%s(), mac [%02x:%02x:%02x:%02x:%02x:%02x],%s,idx:%d,id:0x%02x\n", ++ __FUNCTION__, value[2], value[3], value[4], value[5], value[6], value[7], ++ ((type == WLFC_CTL_TYPE_MACDESC_ADD) ? "ADD":"DEL"), ++ WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]), value[0]); ++ ++ table = wlfc->destination_entries.nodes; ++ table_index = WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]); ++ ifid = value[1]; ++ ea = &value[2]; ++ ++ if (type == WLFC_CTL_TYPE_MACDESC_ADD) { ++ existing_index = dhd_wlfc_find_mac_desc_id_from_mac(dhd, &value[2]); ++ if (existing_index == WLFC_MAC_DESC_ID_INVALID) { ++ /* this MAC entry does not exist, create one */ ++ if (!table[table_index].occupied) { ++ table[table_index].mac_handle = value[0]; ++ rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], ++ eWLFC_MAC_ENTRY_ACTION_ADD, ifid, ++ wlfc->destination_entries.interfaces[ifid].iftype, ++ ea); ++ } ++ else { ++ /* the space should have been empty, but it's not */ ++ wlfc->stats.mac_update_failed++; ++ } ++ } ++ else { ++ /* ++ there is an existing entry, move it to new index ++ if necessary. ++ */ ++ if (existing_index != table_index) { ++ /* if we already have an entry, free the old one */ ++ table[existing_index].occupied = 0; ++ table[existing_index].state = WLFC_STATE_CLOSE; ++ table[existing_index].requested_credit = 0; ++ table[existing_index].interface_id = 0; ++ /* enable after packets are queued-deqeued properly. ++ pktq_flush(dhd->osh, &table[existing_index].psq, FALSE, NULL, 0); ++ */ ++ } ++ } ++ } ++ if (type == WLFC_CTL_TYPE_MACDESC_DEL) { ++ if (table[table_index].occupied) { ++ rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], ++ eWLFC_MAC_ENTRY_ACTION_DEL, ifid, ++ wlfc->destination_entries.interfaces[ifid].iftype, ++ ea); ++ } ++ else { ++ /* the space should have been occupied, but it's not */ ++ wlfc->stats.mac_update_failed++; ++ } ++ } ++ BCM_REFERENCE(rc); ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type) ++{ ++ /* Handle PS on/off indication */ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_mac_descriptor_t* desc; ++ uint8 mac_handle = value[0]; ++ int i; ++ ++ table = wlfc->destination_entries.nodes; ++ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; ++ if (desc->occupied) { ++ /* a fresh PS mode should wipe old ps credits? */ ++ desc->requested_credit = 0; ++ if (type == WLFC_CTL_TYPE_MAC_OPEN) { ++ desc->state = WLFC_STATE_OPEN; ++ DHD_WLFC_CTRINC_MAC_OPEN(desc); ++ } ++ else { ++ desc->state = WLFC_STATE_CLOSE; ++ DHD_WLFC_CTRINC_MAC_CLOSE(desc); ++ /* ++ Indicate to firmware if there is any traffic pending. ++ */ ++ for (i = AC_BE; i < AC_COUNT; i++) { ++ _dhd_wlfc_traffic_pending_check(wlfc, desc, i); ++ } ++ } ++ } ++ else { ++ wlfc->stats.psmode_update_failed++; ++ } ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type) ++{ ++ /* Handle PS on/off indication */ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ uint8 if_id = value[0]; ++ ++ if (if_id < WLFC_MAX_IFNUM) { ++ table = wlfc->destination_entries.interfaces; ++ if (table[if_id].occupied) { ++ if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) { ++ table[if_id].state = WLFC_STATE_OPEN; ++ /* AP6211_DEBUG("INTERFACE[%d] OPEN\n", if_id); */ ++ } ++ else { ++ table[if_id].state = WLFC_STATE_CLOSE; ++ /* AP6211_DEBUG("INTERFACE[%d] CLOSE\n", if_id); */ ++ } ++ return BCME_OK; ++ } ++ } ++ wlfc->stats.interface_update_failed++; ++ ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_credit_request(dhd_pub_t *dhd, uint8* value) ++{ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_mac_descriptor_t* desc; ++ uint8 mac_handle; ++ uint8 credit; ++ ++ table = wlfc->destination_entries.nodes; ++ mac_handle = value[1]; ++ credit = value[0]; ++ ++ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; ++ if (desc->occupied) { ++ desc->requested_credit = credit; ++ ++ desc->ac_bitmap = value[2]; ++ } ++ else { ++ wlfc->stats.credit_request_failed++; ++ } ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_packet_request(dhd_pub_t *dhd, uint8* value) ++{ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_mac_descriptor_t* desc; ++ uint8 mac_handle; ++ uint8 packet_count; ++ ++ table = wlfc->destination_entries.nodes; ++ mac_handle = value[1]; ++ packet_count = value[0]; ++ ++ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; ++ if (desc->occupied) { ++ desc->requested_packet = packet_count; ++ ++ desc->ac_bitmap = value[2]; ++ } ++ else { ++ wlfc->stats.packet_request_failed++; ++ } ++ return BCME_OK; ++} ++ ++static void ++dhd_wlfc_reorderinfo_indicate(uint8 *val, uint8 len, uchar *info_buf, uint *info_len) ++{ ++ if (info_len) { ++ if (info_buf) { ++ bcopy(val, info_buf, len); ++ *info_len = len; ++ } ++ else ++ *info_len = 0; ++ } ++} ++ ++static int ++dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar *reorder_info_buf, ++ uint *reorder_info_len) ++{ ++ uint8 type, len; ++ uint8* value; ++ uint8* tmpbuf; ++ uint16 remainder = tlv_hdr_len; ++ uint16 processed = 0; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ tmpbuf = (uint8*)PKTDATA(dhd->osh, pktbuf); ++ if (remainder) { ++ while ((processed < (WLFC_MAX_PENDING_DATALEN * 2)) && (remainder > 0)) { ++ type = tmpbuf[processed]; ++ if (type == WLFC_CTL_TYPE_FILLER) { ++ remainder -= 1; ++ processed += 1; ++ continue; ++ } ++ ++ len = tmpbuf[processed + 1]; ++ value = &tmpbuf[processed + 2]; ++ ++ if (remainder < (2 + len)) ++ break; ++ ++ remainder -= 2 + len; ++ processed += 2 + len; ++ if (type == WLFC_CTL_TYPE_TXSTATUS) ++ dhd_wlfc_txstatus_update(dhd, value); ++ if (type == WLFC_CTL_TYPE_COMP_TXSTATUS) ++ dhd_wlfc_compressed_txstatus_update(dhd, value, len); ++ ++ else if (type == WLFC_CTL_TYPE_HOST_REORDER_RXPKTS) ++ dhd_wlfc_reorderinfo_indicate(value, len, reorder_info_buf, ++ reorder_info_len); ++ else if (type == WLFC_CTL_TYPE_FIFO_CREDITBACK) ++ dhd_wlfc_fifocreditback_indicate(dhd, value); ++ ++ else if (type == WLFC_CTL_TYPE_RSSI) ++ dhd_wlfc_rssi_indicate(dhd, value); ++ ++ else if (type == WLFC_CTL_TYPE_MAC_REQUEST_CREDIT) ++ dhd_wlfc_credit_request(dhd, value); ++ ++ else if (type == WLFC_CTL_TYPE_MAC_REQUEST_PACKET) ++ dhd_wlfc_packet_request(dhd, value); ++ ++ else if ((type == WLFC_CTL_TYPE_MAC_OPEN) || ++ (type == WLFC_CTL_TYPE_MAC_CLOSE)) ++ dhd_wlfc_psmode_update(dhd, value, type); ++ ++ else if ((type == WLFC_CTL_TYPE_MACDESC_ADD) || ++ (type == WLFC_CTL_TYPE_MACDESC_DEL)) ++ dhd_wlfc_mac_table_update(dhd, value, type); ++ ++ else if (type == WLFC_CTL_TYPE_TRANS_ID) ++ dhd_wlfc_dbg_senum_check(dhd, value); ++ ++ else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) || ++ (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) { ++ dhd_wlfc_interface_update(dhd, value, type); ++ } ++ } ++ if (remainder != 0) { ++ /* trouble..., something is not right */ ++ wlfc->stats.tlv_parse_failed++; ++ } ++ } ++ return BCME_OK; ++} ++ ++int ++dhd_wlfc_init(dhd_pub_t *dhd) ++{ ++ char iovbuf[12]; /* Room for "tlv" + '\0' + parameter */ ++ /* enable all signals & indicate host proptxstatus logic is active */ ++ uint32 tlv = dhd->wlfc_enabled? ++ WLFC_FLAGS_RSSI_SIGNALS | ++ WLFC_FLAGS_XONXOFF_SIGNALS | ++ WLFC_FLAGS_CREDIT_STATUS_SIGNALS | ++ WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | ++ WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; ++ /* WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; */ ++ ++ ++ /* ++ try to enable/disable signaling by sending "tlv" iovar. if that fails, ++ fallback to no flow control? Print a message for now. ++ */ ++ ++ /* enable proptxtstatus signaling by default */ ++ bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); ++ if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { ++ AP6211_ERR("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n"); ++ } ++ else { ++ /* ++ Leaving the message for now, it should be removed after a while; once ++ the tlv situation is stable. ++ */ ++ AP6211_DEBUG("dhd_wlfc_init(): successfully %s bdcv2 tlv signaling, %d\n", ++ dhd->wlfc_enabled?"enabled":"disabled", tlv); ++ } ++ return BCME_OK; ++} ++ ++int ++dhd_wlfc_enable(dhd_pub_t *dhd) ++{ ++ int i; ++ athost_wl_status_info_t* wlfc; ++ ++ AP6211_DEBUG("Enter %s\n", __FUNCTION__); ++ ++ if (!dhd->wlfc_enabled || dhd->wlfc_state) ++ return BCME_OK; ++ ++ /* allocate space to track txstatus propagated from firmware */ ++ dhd->wlfc_state = MALLOC(dhd->osh, sizeof(athost_wl_status_info_t)); ++ if (dhd->wlfc_state == NULL) ++ return BCME_NOMEM; ++ ++ /* initialize state space */ ++ wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ memset(wlfc, 0, sizeof(athost_wl_status_info_t)); ++ ++ /* remember osh & dhdp */ ++ wlfc->osh = dhd->osh; ++ wlfc->dhdp = dhd; ++ ++ wlfc->hanger = ++ dhd_wlfc_hanger_create(dhd->osh, WLFC_HANGER_MAXITEMS); ++ if (wlfc->hanger == NULL) { ++ MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); ++ dhd->wlfc_state = NULL; ++ return BCME_NOMEM; ++ } ++ ++ /* initialize all interfaces to accept traffic */ ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ wlfc->hostif_flow_state[i] = OFF; ++ } ++ ++ /* ++ create the SENDQ containing ++ sub-queues for all AC precedences + 1 for bc/mc traffic ++ */ ++ pktq_init(&wlfc->SENDQ, (AC_COUNT + 1), WLFC_SENDQ_LEN); ++ ++ wlfc->destination_entries.other.state = WLFC_STATE_OPEN; ++ /* bc/mc FIFO is always open [credit aside], i.e. b[5] */ ++ wlfc->destination_entries.other.ac_bitmap = 0x1f; ++ wlfc->destination_entries.other.interface_id = 0; ++ ++ wlfc->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT; ++ ++ wlfc->allow_credit_borrow = TRUE; ++ wlfc->borrow_defer_timestamp = 0; ++ ++ return BCME_OK; ++} ++ ++/* release all packet resources */ ++void ++dhd_wlfc_cleanup(dhd_pub_t *dhd) ++{ ++ int i; ++ int total_entries; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_hanger_t* h; ++ int prec; ++ void *pkt = NULL; ++ struct pktq *txq = NULL; ++ ++ AP6211_DEBUG("Enter %s\n", __FUNCTION__); ++ if (dhd->wlfc_state == NULL) ++ return; ++ /* flush bus->txq */ ++ txq = dhd_bus_txq(dhd->bus); ++ ++ /* any in the hanger? */ ++ h = (wlfc_hanger_t*)wlfc->hanger; ++ total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t); ++ /* search all entries, include nodes as well as interfaces */ ++ table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries; ++ ++ for (i = 0; i < total_entries; i++) { ++ if (table[i].occupied) { ++ if (table[i].psq.len) { ++ AP6211_DEBUG("%s(): DELAYQ[%d].len = %d\n", ++ __FUNCTION__, i, table[i].psq.len); ++ /* release packets held in DELAYQ */ ++ pktq_flush(wlfc->osh, &table[i].psq, TRUE, NULL, 0); ++ } ++ table[i].occupied = 0; ++ } ++ } ++ /* release packets held in SENDQ */ ++ if (wlfc->SENDQ.len) ++ pktq_flush(wlfc->osh, &wlfc->SENDQ, TRUE, NULL, 0); ++ for (prec = 0; prec < txq->num_prec; prec++) { ++ pkt = pktq_pdeq(txq, prec); ++ while (pkt) { ++ for (i = 0; i < h->max_items; i++) { ++ if (pkt == h->items[i].pkt) { ++ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { ++ PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ h->items[i].pkt = NULL; ++ h->items[i].identifier = 0; ++ } else if (h->items[i].state == ++ WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { ++ /* These are already freed from the psq */ ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } ++ break; ++ } ++ } ++ pkt = pktq_pdeq(txq, prec); ++ } ++ } ++ /* flush remained pkt in hanger queue, not in bus->txq */ ++ for (i = 0; i < h->max_items; i++) { ++ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { ++ PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } else if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { ++ /* These are freed from the psq so no need to free again */ ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } ++ } ++ ++ return; ++} ++ ++void ++dhd_wlfc_deinit(dhd_pub_t *dhd) ++{ ++ /* cleanup all psq related resources */ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ ++ AP6211_DEBUG("Enter %s\n", __FUNCTION__); ++ ++ dhd_os_wlfc_block(dhd); ++ if (dhd->wlfc_state == NULL) { ++ dhd_os_wlfc_unblock(dhd); ++ return; ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ int i; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; ++ for (i = 0; i < h->max_items; i++) { ++ if (h->items[i].state != WLFC_HANGER_ITEM_STATE_FREE) { ++ AP6211_DEBUG("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n", ++ __FUNCTION__, i, h->items[i].pkt, ++ DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt))); ++ } ++ } ++ } ++#endif ++ /* delete hanger */ ++ dhd_wlfc_hanger_delete(dhd->osh, wlfc->hanger); ++ ++ /* free top structure */ ++ MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); ++ dhd->wlfc_state = NULL; ++ dhd_os_wlfc_unblock(dhd); ++ ++ return; ++} ++#endif /* PROP_TXSTATUS */ ++ ++void ++dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) ++{ ++ bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid); ++#ifdef PROP_TXSTATUS ++ dhd_os_wlfc_block(dhdp); ++ if (dhdp->wlfc_state) ++ dhd_wlfc_dump(dhdp, strbuf); ++ dhd_os_wlfc_unblock(dhdp); ++#endif ++} ++ ++void ++dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) ++{ ++#ifdef BDC ++ struct bdc_header *h; ++#endif /* BDC */ ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++#ifdef BDC ++ /* Push BDC header used to convey priority for buses that don't */ ++ ++ PKTPUSH(dhd->osh, pktbuf, BDC_HEADER_LEN); ++ ++ h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); ++ ++ h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); ++ if (PKTSUMNEEDED(pktbuf)) ++ h->flags |= BDC_FLAG_SUM_NEEDED; ++ ++ ++ h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK); ++ h->flags2 = 0; ++ h->dataOffset = 0; ++#endif /* BDC */ ++ BDC_SET_IF_IDX(h, ifidx); ++} ++ ++int ++dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_info, ++ uint *reorder_info_len) ++{ ++#ifdef BDC ++ struct bdc_header *h; ++#endif ++ uint8 data_offset = 0; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++#ifdef BDC ++ if (reorder_info_len) ++ *reorder_info_len = 0; ++ /* Pop BDC header used to convey priority for buses that don't */ ++ ++ if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) { ++ AP6211_ERR("%s: rx data too short (%d < %d)\n", __FUNCTION__, ++ PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN); ++ return BCME_ERROR; ++ } ++ ++ h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); ++ ++#if defined(NDIS630) ++ h->dataOffset = 0; ++#endif ++ ++ if (!ifidx) { ++ /* for tx packet, skip the analysis */ ++ data_offset = h->dataOffset; ++ PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); ++ goto exit; ++ } ++ ++ if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) { ++ AP6211_ERR("%s: rx data ifnum out of range (%d)\n", ++ __FUNCTION__, *ifidx); ++ return BCME_ERROR; ++ } ++ ++ if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) { ++ AP6211_ERR("%s: non-BDC packet received, flags = 0x%x\n", ++ dhd_ifname(dhd, *ifidx), h->flags); ++ if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) == BDC_PROTO_VER_1) ++ h->dataOffset = 0; ++ else ++ return BCME_ERROR; ++ } ++ ++ if (h->flags & BDC_FLAG_SUM_GOOD) { ++ AP6211_DEBUG("%s: BDC packet received with good rx-csum, flags 0x%x\n", ++ dhd_ifname(dhd, *ifidx), h->flags); ++ PKTSETSUMGOOD(pktbuf, TRUE); ++ } ++ ++ PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK)); ++ data_offset = h->dataOffset; ++ PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); ++#endif /* BDC */ ++ ++#if !defined(NDIS630) ++ if (PKTLEN(dhd->osh, pktbuf) < (uint32) (data_offset << 2)) { ++ AP6211_ERR("%s: rx data too short (%d < %d)\n", __FUNCTION__, ++ PKTLEN(dhd->osh, pktbuf), (data_offset * 4)); ++ return BCME_ERROR; ++ } ++#endif ++#ifdef PROP_TXSTATUS ++ if (dhd->wlfc_state && ++ ((athost_wl_status_info_t*)dhd->wlfc_state)->proptxstatus_mode ++ != WLFC_FCMODE_NONE && ++ (!DHD_PKTTAG_PKTDIR(PKTTAG(pktbuf)))) { ++ /* ++ - parse txstatus only for packets that came from the firmware ++ */ ++ dhd_os_wlfc_block(dhd); ++ dhd_wlfc_parse_header_info(dhd, pktbuf, (data_offset << 2), ++ reorder_buf_info, reorder_info_len); ++ ((athost_wl_status_info_t*)dhd->wlfc_state)->stats.dhd_hdrpulls++; ++ dhd_os_wlfc_unblock(dhd); ++ } ++#endif /* PROP_TXSTATUS */ ++ ++exit: ++#if !defined(NDIS630) ++ PKTPULL(dhd->osh, pktbuf, (data_offset << 2)); ++#endif ++ return 0; ++} ++ ++#if defined(PROP_TXSTATUS) ++void ++dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd) ++{ ++ if (dhd->wlfc_state && ++ (((athost_wl_status_info_t*)dhd->wlfc_state)->proptxstatus_mode ++ != WLFC_FCMODE_NONE)) { ++ dhd_os_wlfc_block(dhd); ++ dhd_wlfc_commit_packets(dhd->wlfc_state, (f_commitpkt_t)dhd_bus_txdata, ++ (void *)dhd->bus); ++ dhd_os_wlfc_unblock(dhd); ++ } ++} ++#endif ++ ++int ++dhd_prot_attach(dhd_pub_t *dhd) ++{ ++ dhd_prot_t *cdc; ++ ++ if (!(cdc = (dhd_prot_t *)DHD_OS_PREALLOC(dhd->osh, DHD_PREALLOC_PROT, ++ sizeof(dhd_prot_t)))) { ++ AP6211_ERR("%s: kmalloc failed\n", __FUNCTION__); ++ goto fail; ++ } ++ memset(cdc, 0, sizeof(dhd_prot_t)); ++ ++ /* ensure that the msg buf directly follows the cdc msg struct */ ++ if ((uintptr)(&cdc->msg + 1) != (uintptr)cdc->buf) { ++ AP6211_ERR("dhd_prot_t is not correctly defined\n"); ++ goto fail; ++ } ++ ++ dhd->prot = cdc; ++#ifdef BDC ++ dhd->hdrlen += BDC_HEADER_LEN; ++#endif ++ dhd->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN; ++ return 0; ++ ++fail: ++#ifndef CONFIG_DHD_USE_STATIC_BUF ++ if (cdc != NULL) ++ MFREE(dhd->osh, cdc, sizeof(dhd_prot_t)); ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ return BCME_NOMEM; ++} ++ ++/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */ ++void ++dhd_prot_detach(dhd_pub_t *dhd) ++{ ++#ifdef PROP_TXSTATUS ++ dhd_wlfc_deinit(dhd); ++#endif ++#ifndef CONFIG_DHD_USE_STATIC_BUF ++ MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t)); ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ dhd->prot = NULL; ++} ++ ++void ++dhd_prot_dstats(dhd_pub_t *dhd) ++{ ++ /* No stats from dongle added yet, copy bus stats */ ++ dhd->dstats.tx_packets = dhd->tx_packets; ++ dhd->dstats.tx_errors = dhd->tx_errors; ++ dhd->dstats.rx_packets = dhd->rx_packets; ++ dhd->dstats.rx_errors = dhd->rx_errors; ++ dhd->dstats.rx_dropped = dhd->rx_dropped; ++ dhd->dstats.multicast = dhd->rx_multicast; ++ return; ++} ++ ++int ++dhd_prot_init(dhd_pub_t *dhd) ++{ ++ int ret = 0; ++ wlc_rev_info_t revinfo; ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ ++ /* Get the device rev info */ ++ memset(&revinfo, 0, sizeof(revinfo)); ++ ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0); ++ if (ret < 0) ++ goto done; ++ ++ ++#if defined(WL_CFG80211) ++ if (dhd_download_fw_on_driverload) ++#endif /* defined(WL_CFG80211) */ ++ ret = dhd_preinit_ioctls(dhd); ++ ++#ifdef PROP_TXSTATUS ++ ret = dhd_wlfc_init(dhd); ++#endif ++ ++ /* Always assumes wl for now */ ++ dhd->iswl = TRUE; ++ ++done: ++ return ret; ++} ++ ++void ++dhd_prot_stop(dhd_pub_t *dhd) ++{ ++ /* Nothing to do for CDC */ ++} ++ ++ ++static void ++dhd_get_hostreorder_pkts(void *osh, struct reorder_info *ptr, void **pkt, ++ uint32 *pkt_count, void **pplast, uint8 start, uint8 end) ++{ ++ uint i; ++ void *plast = NULL, *p; ++ uint32 pkt_cnt = 0; ++ ++ if (ptr->pend_pkts == 0) { ++ AP6211_DEBUG("%s: no packets in reorder queue \n", __FUNCTION__); ++ *pplast = NULL; ++ *pkt_count = 0; ++ *pkt = NULL; ++ return; ++ } ++ if (start == end) ++ i = ptr->max_idx + 1; ++ else { ++ if (start > end) ++ i = ((ptr->max_idx + 1) - start) + end; ++ else ++ i = end - start; ++ } ++ while (i) { ++ p = (void *)(ptr->p[start]); ++ ptr->p[start] = NULL; ++ ++ if (p != NULL) { ++ if (plast == NULL) ++ *pkt = p; ++ else ++ PKTSETNEXT(osh, plast, p); ++ ++ plast = p; ++ pkt_cnt++; ++ } ++ i--; ++ if (start++ == ptr->max_idx) ++ start = 0; ++ } ++ *pplast = plast; ++ *pkt_count = (uint32)pkt_cnt; ++} ++ ++int ++dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, ++ void **pkt, uint32 *pkt_count) ++{ ++ uint8 flow_id, max_idx, cur_idx, exp_idx; ++ struct reorder_info *ptr; ++ uint8 flags; ++ void *cur_pkt, *plast = NULL; ++ uint32 cnt = 0; ++ ++ if (pkt == NULL) { ++ if (pkt_count != NULL) ++ *pkt_count = 0; ++ return 0; ++ } ++ ++ flow_id = reorder_info_buf[WLHOST_REORDERDATA_FLOWID_OFFSET]; ++ flags = reorder_info_buf[WLHOST_REORDERDATA_FLAGS_OFFSET]; ++ ++ AP6211_DEBUG("flow_id %d, flags 0x%02x, idx(%d, %d, %d)\n", flow_id, flags, ++ reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET], ++ reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET], ++ reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]); ++ ++ /* validate flags and flow id */ ++ if (flags == 0xFF) { ++ AP6211_ERR("%s: invalid flags...so ignore this packet\n", __FUNCTION__); ++ *pkt_count = 1; ++ return 0; ++ } ++ ++ cur_pkt = *pkt; ++ *pkt = NULL; ++ ++ ptr = dhd->reorder_bufs[flow_id]; ++ if (flags & WLHOST_REORDERDATA_DEL_FLOW) { ++ uint32 buf_size = sizeof(struct reorder_info); ++ ++ AP6211_DEBUG("%s: Flags indicating to delete a flow id %d\n", ++ __FUNCTION__, flow_id); ++ ++ if (ptr == NULL) { ++ AP6211_ERR("%s: received flags to cleanup, but no flow (%d) yet\n", ++ __FUNCTION__, flow_id); ++ *pkt_count = 1; ++ *pkt = cur_pkt; ++ return 0; ++ } ++ ++ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ++ ptr->exp_idx, ptr->exp_idx); ++ /* set it to the last packet */ ++ if (plast) { ++ PKTSETNEXT(dhd->osh, plast, cur_pkt); ++ cnt++; ++ } ++ else { ++ if (cnt != 0) { ++ AP6211_ERR("%s: del flow: something fishy, pending packets %d\n", ++ __FUNCTION__, cnt); ++ } ++ *pkt = cur_pkt; ++ cnt = 1; ++ } ++ buf_size += ((ptr->max_idx + 1) * sizeof(void *)); ++ MFREE(dhd->osh, ptr, buf_size); ++ dhd->reorder_bufs[flow_id] = NULL; ++ *pkt_count = cnt; ++ return 0; ++ } ++ /* all the other cases depend on the existance of the reorder struct for that flow id */ ++ if (ptr == NULL) { ++ uint32 buf_size_alloc = sizeof(reorder_info_t); ++ max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; ++ ++ buf_size_alloc += ((max_idx + 1) * sizeof(void*)); ++ /* allocate space to hold the buffers, index etc */ ++ ++ AP6211_DEBUG("%s: alloc buffer of size %d size, reorder info id %d, maxidx %d\n", ++ __FUNCTION__, buf_size_alloc, flow_id, max_idx); ++ ptr = (struct reorder_info *)MALLOC(dhd->osh, buf_size_alloc); ++ if (ptr == NULL) { ++ AP6211_ERR("%s: Malloc failed to alloc buffer\n", __FUNCTION__); ++ *pkt_count = 1; ++ return 0; ++ } ++ bzero(ptr, buf_size_alloc); ++ dhd->reorder_bufs[flow_id] = ptr; ++ ptr->p = (void *)(ptr+1); ++ ptr->max_idx = max_idx; ++ } ++ if (flags & WLHOST_REORDERDATA_NEW_HOLE) { ++ AP6211_DEBUG("%s: new hole, so cleanup pending buffers\n", __FUNCTION__); ++ if (ptr->pend_pkts) { ++ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ++ ptr->exp_idx, ptr->exp_idx); ++ ptr->pend_pkts = 0; ++ } ++ ptr->cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; ++ ptr->exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; ++ ptr->max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; ++ ptr->p[ptr->cur_idx] = cur_pkt; ++ ptr->pend_pkts++; ++ *pkt_count = cnt; ++ } ++ else if (flags & WLHOST_REORDERDATA_CURIDX_VALID) { ++ cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; ++ exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; ++ ++ ++ if ((exp_idx == ptr->exp_idx) && (cur_idx != ptr->exp_idx)) { ++ /* still in the current hole */ ++ /* enqueue the current on the buffer chain */ ++ if (ptr->p[cur_idx] != NULL) { ++ AP6211_DEBUG("%s: HOLE: ERROR buffer pending..free it\n", ++ __FUNCTION__); ++ PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); ++ ptr->p[cur_idx] = NULL; ++ } ++ ptr->p[cur_idx] = cur_pkt; ++ ptr->pend_pkts++; ++ ptr->cur_idx = cur_idx; ++ AP6211_DEBUG("%s: fill up a hole..pending packets is %d\n", ++ __FUNCTION__, ptr->pend_pkts); ++ *pkt_count = 0; ++ *pkt = NULL; ++ } ++ else if (ptr->exp_idx == cur_idx) { ++ /* got the right one ..flush from cur to exp and update exp */ ++ AP6211_DEBUG("%s: got the right one now, cur_idx is %d\n", ++ __FUNCTION__, cur_idx); ++ if (ptr->p[cur_idx] != NULL) { ++ AP6211_DEBUG("%s: Error buffer pending..free it\n", ++ __FUNCTION__); ++ PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); ++ ptr->p[cur_idx] = NULL; ++ } ++ ptr->p[cur_idx] = cur_pkt; ++ ptr->pend_pkts++; ++ ++ ptr->cur_idx = cur_idx; ++ ptr->exp_idx = exp_idx; ++ ++ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ++ cur_idx, exp_idx); ++ ptr->pend_pkts -= (uint8)cnt; ++ *pkt_count = cnt; ++ AP6211_DEBUG("%s: freeing up buffers %d, still pending %d\n", ++ __FUNCTION__, cnt, ptr->pend_pkts); ++ } ++ else { ++ uint8 end_idx; ++ bool flush_current = FALSE; ++ /* both cur and exp are moved now .. */ ++ AP6211_DEBUG("%s:, flow %d, both moved, cur %d(%d), exp %d(%d)\n", ++ __FUNCTION__, flow_id, ptr->cur_idx, cur_idx, ++ ptr->exp_idx, exp_idx); ++ if (flags & WLHOST_REORDERDATA_FLUSH_ALL) ++ end_idx = ptr->exp_idx; ++ else ++ end_idx = exp_idx; ++ ++ /* flush pkts first */ ++ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ++ ptr->exp_idx, end_idx); ++ ++ if (cur_idx == ptr->max_idx) { ++ if (exp_idx == 0) ++ flush_current = TRUE; ++ } else { ++ if (exp_idx == cur_idx + 1) ++ flush_current = TRUE; ++ } ++ if (flush_current) { ++ if (plast) ++ PKTSETNEXT(dhd->osh, plast, cur_pkt); ++ else ++ *pkt = cur_pkt; ++ cnt++; ++ } ++ else { ++ ptr->p[cur_idx] = cur_pkt; ++ ptr->pend_pkts++; ++ } ++ ptr->exp_idx = exp_idx; ++ ptr->cur_idx = cur_idx; ++ *pkt_count = cnt; ++ } ++ } ++ else { ++ uint8 end_idx; ++ /* no real packet but update to exp_seq...that means explicit window move */ ++ exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; ++ ++ AP6211_DEBUG("%s: move the window, cur_idx is %d, exp is %d, new exp is %d\n", ++ __FUNCTION__, ptr->cur_idx, ptr->exp_idx, exp_idx); ++ if (flags & WLHOST_REORDERDATA_FLUSH_ALL) ++ end_idx = ptr->exp_idx; ++ else ++ end_idx = exp_idx; ++ ++ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ptr->exp_idx, end_idx); ++ ptr->pend_pkts -= (uint8)cnt; ++ if (plast) ++ PKTSETNEXT(dhd->osh, plast, cur_pkt); ++ else ++ *pkt = cur_pkt; ++ cnt++; ++ *pkt_count = cnt; ++ /* set the new expected idx */ ++ ptr->exp_idx = exp_idx; ++ } ++ return 0; ++} +diff --git a/drivers/net/wireless/ap6211/dhd_cfg80211.c b/drivers/net/wireless/ap6211/dhd_cfg80211.c +new file mode 100755 +index 0000000..8cb440e +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_cfg80211.c +@@ -0,0 +1,680 @@ ++/* ++ * Linux cfg80211 driver - Dongle Host Driver (DHD) related ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#ifdef PKT_FILTER_SUPPORT ++#include ++#include ++#endif ++ ++extern struct wl_priv *wlcfg_drv_priv; ++ ++#ifdef PKT_FILTER_SUPPORT ++extern uint dhd_pkt_filter_enable; ++extern uint dhd_master_mode; ++extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); ++#endif ++ ++static int dhd_dongle_up = FALSE; ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++static s32 wl_dongle_up(struct net_device *ndev, u32 up); ++ ++/** ++ * Function implementations ++ */ ++ ++s32 dhd_cfg80211_init(struct wl_priv *wl) ++{ ++ dhd_dongle_up = FALSE; ++ return 0; ++} ++ ++s32 dhd_cfg80211_deinit(struct wl_priv *wl) ++{ ++ dhd_dongle_up = FALSE; ++ return 0; ++} ++ ++s32 dhd_cfg80211_down(struct wl_priv *wl) ++{ ++ dhd_dongle_up = FALSE; ++ return 0; ++} ++ ++s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val) ++{ ++ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); ++ dhd->op_mode |= val; ++ AP6211_ERR("Set : op_mode=0x%04x\n", dhd->op_mode); ++#ifdef ARP_OFFLOAD_SUPPORT ++ if (dhd->arp_version == 1) { ++ /* IF P2P is enabled, disable arpoe */ ++ dhd_arp_offload_set(dhd, 0); ++ dhd_arp_offload_enable(dhd, false); ++ } ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++ return 0; ++} ++ ++s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl) ++{ ++ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); ++ dhd->op_mode &= ~(DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE); ++ AP6211_ERR("Clean : op_mode=0x%04x\n", dhd->op_mode); ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ if (dhd->arp_version == 1) { ++ /* IF P2P is disabled, enable arpoe back for STA mode. */ ++ dhd_arp_offload_set(dhd, dhd_arp_mode); ++ dhd_arp_offload_enable(dhd, true); ++ } ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++ return 0; ++} ++ ++static s32 wl_dongle_up(struct net_device *ndev, u32 up) ++{ ++ s32 err = 0; ++ ++ err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_UP error (%d)\n", err); ++ } ++ return err; ++} ++s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock) ++{ ++#ifndef DHD_SDALIGN ++#define DHD_SDALIGN 32 ++#endif ++ struct net_device *ndev; ++ s32 err = 0; ++ ++ AP6211_DEBUG("In\n"); ++ if (dhd_dongle_up) { ++ AP6211_ERR("Dongle is already up\n"); ++ return err; ++ } ++ ++ ndev = wl_to_prmry_ndev(wl); ++ ++ if (need_lock) ++ rtnl_lock(); ++ ++ err = wl_dongle_up(ndev, 0); ++ if (unlikely(err)) { ++ AP6211_ERR("wl_dongle_up failed\n"); ++ goto default_conf_out; ++ } ++ dhd_dongle_up = true; ++ ++default_conf_out: ++ if (need_lock) ++ rtnl_unlock(); ++ return err; ++ ++} ++ ++ ++/* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */ ++#define COEX_DHCP ++ ++#if defined(COEX_DHCP) ++ ++/* use New SCO/eSCO smart YG suppression */ ++#define BT_DHCP_eSCO_FIX ++/* this flag boost wifi pkt priority to max, caution: -not fair to sco */ ++#define BT_DHCP_USE_FLAGS ++/* T1 start SCO/ESCo priority suppression */ ++#define BT_DHCP_OPPR_WIN_TIME 2500 ++/* T2 turn off SCO/SCO supperesion is (timeout) */ ++#define BT_DHCP_FLAG_FORCE_TIME 5500 ++ ++enum wl_cfg80211_btcoex_status { ++ BT_DHCP_IDLE, ++ BT_DHCP_START, ++ BT_DHCP_OPPR_WIN, ++ BT_DHCP_FLAG_FORCE_TIMEOUT ++}; ++ ++/* ++ * get named driver variable to uint register value and return error indication ++ * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, ®_value) ++ */ ++static int ++dev_wlc_intvar_get_reg(struct net_device *dev, char *name, ++ uint reg, int *retval) ++{ ++ union { ++ char buf[WLC_IOCTL_SMLEN]; ++ int val; ++ } var; ++ int error; ++ ++ bcm_mkiovar(name, (char *)(®), sizeof(reg), ++ (char *)(&var), sizeof(var.buf)); ++ error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false); ++ ++ *retval = dtoh32(var.val); ++ return (error); ++} ++ ++static int ++dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) ++ char ioctlbuf_local[1024]; ++#else ++ static char ioctlbuf_local[1024]; ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ ++ ++ bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local)); ++ ++ return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true)); ++} ++/* ++get named driver variable to uint register value and return error indication ++calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value) ++*/ ++static int ++dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val) ++{ ++ char reg_addr[8]; ++ ++ memset(reg_addr, 0, sizeof(reg_addr)); ++ memcpy((char *)®_addr[0], (char *)addr, 4); ++ memcpy((char *)®_addr[4], (char *)val, 4); ++ ++ return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr))); ++} ++ ++static bool btcoex_is_sco_active(struct net_device *dev) ++{ ++ int ioc_res = 0; ++ bool res = FALSE; ++ int sco_id_cnt = 0; ++ int param27; ++ int i; ++ ++ for (i = 0; i < 12; i++) { ++ ++ ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, ¶m27); ++ ++ AP6211_DEBUG("%s, sample[%d], btc params: 27:%x\n", ++ __FUNCTION__, i, param27); ++ ++ if (ioc_res < 0) { ++ AP6211_ERR("%s ioc read btc params error\n", __FUNCTION__); ++ break; ++ } ++ ++ if ((param27 & 0x6) == 2) { /* count both sco & esco */ ++ sco_id_cnt++; ++ } ++ ++ if (sco_id_cnt > 2) { ++ AP6211_DEBUG("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n", ++ __FUNCTION__, sco_id_cnt, i); ++ res = TRUE; ++ break; ++ } ++ ++ msleep(5); ++ } ++ ++ return res; ++} ++ ++#if defined(BT_DHCP_eSCO_FIX) ++/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */ ++static int set_btc_esco_params(struct net_device *dev, bool trump_sco) ++{ ++ static bool saved_status = FALSE; ++ ++ char buf_reg50va_dhcp_on[8] = ++ { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 }; ++ char buf_reg51va_dhcp_on[8] = ++ { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; ++ char buf_reg64va_dhcp_on[8] = ++ { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; ++ char buf_reg65va_dhcp_on[8] = ++ { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; ++ char buf_reg71va_dhcp_on[8] = ++ { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; ++ uint32 regaddr; ++ static uint32 saved_reg50; ++ static uint32 saved_reg51; ++ static uint32 saved_reg64; ++ static uint32 saved_reg65; ++ static uint32 saved_reg71; ++ ++ if (trump_sco) { ++ /* this should reduce eSCO agressive retransmit ++ * w/o breaking it ++ */ ++ ++ /* 1st save current */ ++ AP6211_DEBUG("Do new SCO/eSCO coex algo {save &" ++ "override}\n"); ++ if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) && ++ (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) && ++ (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) && ++ (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) && ++ (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) { ++ saved_status = TRUE; ++ AP6211_DEBUG("%s saved bt_params[50,51,64,65,71]:" ++ "0x%x 0x%x 0x%x 0x%x 0x%x\n", ++ __FUNCTION__, saved_reg50, saved_reg51, ++ saved_reg64, saved_reg65, saved_reg71); ++ } else { ++ AP6211_ERR(":%s: save btc_params failed\n", ++ __FUNCTION__); ++ saved_status = FALSE; ++ return -1; ++ } ++ ++ AP6211_DEBUG("override with [50,51,64,65,71]:" ++ "0x%x 0x%x 0x%x 0x%x 0x%x\n", ++ *(u32 *)(buf_reg50va_dhcp_on+4), ++ *(u32 *)(buf_reg51va_dhcp_on+4), ++ *(u32 *)(buf_reg64va_dhcp_on+4), ++ *(u32 *)(buf_reg65va_dhcp_on+4), ++ *(u32 *)(buf_reg71va_dhcp_on+4)); ++ ++ dev_wlc_bufvar_set(dev, "btc_params", ++ (char *)&buf_reg50va_dhcp_on[0], 8); ++ dev_wlc_bufvar_set(dev, "btc_params", ++ (char *)&buf_reg51va_dhcp_on[0], 8); ++ dev_wlc_bufvar_set(dev, "btc_params", ++ (char *)&buf_reg64va_dhcp_on[0], 8); ++ dev_wlc_bufvar_set(dev, "btc_params", ++ (char *)&buf_reg65va_dhcp_on[0], 8); ++ dev_wlc_bufvar_set(dev, "btc_params", ++ (char *)&buf_reg71va_dhcp_on[0], 8); ++ ++ saved_status = TRUE; ++ } else if (saved_status) { ++ /* restore previously saved bt params */ ++ AP6211_DEBUG("Do new SCO/eSCO coex algo {save &" ++ "override}\n"); ++ ++ regaddr = 50; ++ dev_wlc_intvar_set_reg(dev, "btc_params", ++ (char *)®addr, (char *)&saved_reg50); ++ regaddr = 51; ++ dev_wlc_intvar_set_reg(dev, "btc_params", ++ (char *)®addr, (char *)&saved_reg51); ++ regaddr = 64; ++ dev_wlc_intvar_set_reg(dev, "btc_params", ++ (char *)®addr, (char *)&saved_reg64); ++ regaddr = 65; ++ dev_wlc_intvar_set_reg(dev, "btc_params", ++ (char *)®addr, (char *)&saved_reg65); ++ regaddr = 71; ++ dev_wlc_intvar_set_reg(dev, "btc_params", ++ (char *)®addr, (char *)&saved_reg71); ++ ++ AP6211_DEBUG("restore bt_params[50,51,64,65,71]:" ++ "0x%x 0x%x 0x%x 0x%x 0x%x\n", ++ saved_reg50, saved_reg51, saved_reg64, ++ saved_reg65, saved_reg71); ++ ++ saved_status = FALSE; ++ } else { ++ AP6211_ERR(":%s att to restore not saved BTCOEX params\n", ++ __FUNCTION__); ++ return -1; ++ } ++ return 0; ++} ++#endif /* BT_DHCP_eSCO_FIX */ ++ ++static void ++wl_cfg80211_bt_setflag(struct net_device *dev, bool set) ++{ ++#if defined(BT_DHCP_USE_FLAGS) ++ char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 }; ++ char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; ++#endif ++ ++ ++#if defined(BT_DHCP_eSCO_FIX) ++ /* set = 1, save & turn on 0 - off & restore prev settings */ ++ set_btc_esco_params(dev, set); ++#endif ++ ++#if defined(BT_DHCP_USE_FLAGS) ++ AP6211_DEBUG("WI-FI priority boost via bt flags, set:%d\n", set); ++ if (set == TRUE) ++ /* Forcing bt_flag7 */ ++ dev_wlc_bufvar_set(dev, "btc_flags", ++ (char *)&buf_flag7_dhcp_on[0], ++ sizeof(buf_flag7_dhcp_on)); ++ else ++ /* Restoring default bt flag7 */ ++ dev_wlc_bufvar_set(dev, "btc_flags", ++ (char *)&buf_flag7_default[0], ++ sizeof(buf_flag7_default)); ++#endif ++} ++ ++static void wl_cfg80211_bt_timerfunc(ulong data) ++{ ++ struct btcoex_info *bt_local = (struct btcoex_info *)data; ++ AP6211_DEBUG("%s\n", __FUNCTION__); ++ bt_local->timer_on = 0; ++ schedule_work(&bt_local->work); ++} ++ ++static void wl_cfg80211_bt_handler(struct work_struct *work) ++{ ++ struct btcoex_info *btcx_inf; ++ ++ btcx_inf = container_of(work, struct btcoex_info, work); ++ ++ if (btcx_inf->timer_on) { ++ btcx_inf->timer_on = 0; ++ del_timer_sync(&btcx_inf->timer); ++ } ++ ++ switch (btcx_inf->bt_state) { ++ case BT_DHCP_START: ++ /* DHCP started ++ * provide OPPORTUNITY window to get DHCP address ++ */ ++ AP6211_DEBUG("%s bt_dhcp stm: started \n", ++ __FUNCTION__); ++ btcx_inf->bt_state = BT_DHCP_OPPR_WIN; ++ mod_timer(&btcx_inf->timer, ++ jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME)); ++ btcx_inf->timer_on = 1; ++ break; ++ ++ case BT_DHCP_OPPR_WIN: ++ if (btcx_inf->dhcp_done) { ++ AP6211_DEBUG("%s DHCP Done before T1 expiration\n", ++ __FUNCTION__); ++ goto btc_coex_idle; ++ } ++ ++ /* DHCP is not over yet, start lowering BT priority ++ * enforce btc_params + flags if necessary ++ */ ++ AP6211_DEBUG("%s DHCP T1:%d expired\n", __FUNCTION__, ++ BT_DHCP_OPPR_WIN_TIME); ++ if (btcx_inf->dev) ++ wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE); ++ btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; ++ mod_timer(&btcx_inf->timer, ++ jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME)); ++ btcx_inf->timer_on = 1; ++ break; ++ ++ case BT_DHCP_FLAG_FORCE_TIMEOUT: ++ if (btcx_inf->dhcp_done) { ++ AP6211_DEBUG("%s DHCP Done before T2 expiration\n", ++ __FUNCTION__); ++ } else { ++ /* Noo dhcp during T1+T2, restore BT priority */ ++ AP6211_DEBUG("%s DHCP wait interval T2:%d" ++ "msec expired\n", __FUNCTION__, ++ BT_DHCP_FLAG_FORCE_TIME); ++ } ++ ++ /* Restoring default bt priority */ ++ if (btcx_inf->dev) ++ wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); ++btc_coex_idle: ++ btcx_inf->bt_state = BT_DHCP_IDLE; ++ btcx_inf->timer_on = 0; ++ break; ++ ++ default: ++ AP6211_ERR("%s error g_status=%d !!!\n", __FUNCTION__, ++ btcx_inf->bt_state); ++ if (btcx_inf->dev) ++ wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); ++ btcx_inf->bt_state = BT_DHCP_IDLE; ++ btcx_inf->timer_on = 0; ++ break; ++ } ++ ++ net_os_wake_unlock(btcx_inf->dev); ++} ++ ++int wl_cfg80211_btcoex_init(struct wl_priv *wl) ++{ ++ struct btcoex_info *btco_inf = NULL; ++ ++ btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL); ++ if (!btco_inf) ++ return -ENOMEM; ++ ++ btco_inf->bt_state = BT_DHCP_IDLE; ++ btco_inf->ts_dhcp_start = 0; ++ btco_inf->ts_dhcp_ok = 0; ++ /* Set up timer for BT */ ++ btco_inf->timer_ms = 10; ++ init_timer(&btco_inf->timer); ++ btco_inf->timer.data = (ulong)btco_inf; ++ btco_inf->timer.function = wl_cfg80211_bt_timerfunc; ++ ++ btco_inf->dev = wl->wdev->netdev; ++ ++ INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler); ++ ++ wl->btcoex_info = btco_inf; ++ return 0; ++} ++ ++void wl_cfg80211_btcoex_deinit(struct wl_priv *wl) ++{ ++ if (!wl->btcoex_info) ++ return; ++ ++ if (wl->btcoex_info->timer_on) { ++ wl->btcoex_info->timer_on = 0; ++ del_timer_sync(&wl->btcoex_info->timer); ++ } ++ ++ cancel_work_sync(&wl->btcoex_info->work); ++ ++ kfree(wl->btcoex_info); ++ wl->btcoex_info = NULL; ++} ++#endif ++ ++int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) ++{ ++ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ char powermode_val = 0; ++ char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 }; ++ char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 }; ++ char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 }; ++ ++ uint32 regaddr; ++ static uint32 saved_reg66; ++ static uint32 saved_reg41; ++ static uint32 saved_reg68; ++ static bool saved_status = FALSE; ++ ++#ifdef COEX_DHCP ++ char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; ++ struct btcoex_info *btco_inf = wl->btcoex_info; ++#endif /* COEX_DHCP */ ++ ++#ifdef PKT_FILTER_SUPPORT ++ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); ++#endif ++ ++ /* Figure out powermode 1 or o command */ ++ strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1); ++ ++ if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { ++ AP6211_DEBUG("%s: DHCP session starts\n", __FUNCTION__); ++ ++#if defined(DHCP_SCAN_SUPPRESS) ++ /* Suppress scan during the DHCP */ ++ wl_cfg80211_scan_suppress(dev, 1); ++#endif /* OEM_ANDROID */ ++ ++#ifdef PKT_FILTER_SUPPORT ++ dhd->dhcp_in_progress = 1; ++ ++ if (dhd->early_suspended) { ++ AP6211_DEBUG("DHCP in progressing , disable packet filter!!!\n"); ++ dhd_enable_packet_filter(0, dhd); ++ } ++#endif ++ ++ /* Retrieve and saved orig regs value */ ++ if ((saved_status == FALSE) && ++ (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && ++ (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && ++ (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { ++ saved_status = TRUE; ++ AP6211_DEBUG("Saved 0x%x 0x%x 0x%x\n", ++ saved_reg66, saved_reg41, saved_reg68); ++ ++ /* Disable PM mode during dhpc session */ ++ ++ /* Disable PM mode during dhpc session */ ++#ifdef COEX_DHCP ++ /* Start BT timer only for SCO connection */ ++ if (btcoex_is_sco_active(dev)) { ++ /* btc_params 66 */ ++ dev_wlc_bufvar_set(dev, "btc_params", ++ (char *)&buf_reg66va_dhcp_on[0], ++ sizeof(buf_reg66va_dhcp_on)); ++ /* btc_params 41 0x33 */ ++ dev_wlc_bufvar_set(dev, "btc_params", ++ (char *)&buf_reg41va_dhcp_on[0], ++ sizeof(buf_reg41va_dhcp_on)); ++ /* btc_params 68 0x190 */ ++ dev_wlc_bufvar_set(dev, "btc_params", ++ (char *)&buf_reg68va_dhcp_on[0], ++ sizeof(buf_reg68va_dhcp_on)); ++ saved_status = TRUE; ++ ++ btco_inf->bt_state = BT_DHCP_START; ++ btco_inf->timer_on = 1; ++ mod_timer(&btco_inf->timer, btco_inf->timer.expires); ++ AP6211_DEBUG("%s enable BT DHCP Timer\n", ++ __FUNCTION__); ++ } ++#endif /* COEX_DHCP */ ++ } ++ else if (saved_status == TRUE) { ++ AP6211_ERR("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__); ++ } ++ } ++ else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) { ++ ++ ++#ifdef PKT_FILTER_SUPPORT ++ dhd->dhcp_in_progress = 0; ++ AP6211_DEBUG("%s: DHCP is complete \n", __FUNCTION__); ++ ++#if defined(DHCP_SCAN_SUPPRESS) ++ /* Since DHCP is complete, enable the scan back */ ++ wl_cfg80211_scan_suppress(dev, 0); ++#endif /* OEM_ANDROID */ ++ ++ /* Enable packet filtering */ ++ if (dhd->early_suspended) { ++ AP6211_DEBUG("DHCP is complete , enable packet filter!!!\n"); ++ dhd_enable_packet_filter(1, dhd); ++ } ++#endif /* PKT_FILTER_SUPPORT */ ++ ++ /* Restoring PM mode */ ++ ++#ifdef COEX_DHCP ++ /* Stop any bt timer because DHCP session is done */ ++ AP6211_DEBUG("%s disable BT DHCP Timer\n", __FUNCTION__); ++ if (btco_inf->timer_on) { ++ btco_inf->timer_on = 0; ++ del_timer_sync(&btco_inf->timer); ++ ++ if (btco_inf->bt_state != BT_DHCP_IDLE) { ++ /* need to restore original btc flags & extra btc params */ ++ AP6211_DEBUG("%s bt->bt_state:%d\n", ++ __FUNCTION__, btco_inf->bt_state); ++ /* wake up btcoex thread to restore btlags+params */ ++ schedule_work(&btco_inf->work); ++ } ++ } ++ ++ /* Restoring btc_flag paramter anyway */ ++ if (saved_status == TRUE) ++ dev_wlc_bufvar_set(dev, "btc_flags", ++ (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); ++#endif /* COEX_DHCP */ ++ ++ /* Restore original values */ ++ if (saved_status == TRUE) { ++ regaddr = 66; ++ dev_wlc_intvar_set_reg(dev, "btc_params", ++ (char *)®addr, (char *)&saved_reg66); ++ regaddr = 41; ++ dev_wlc_intvar_set_reg(dev, "btc_params", ++ (char *)®addr, (char *)&saved_reg41); ++ regaddr = 68; ++ dev_wlc_intvar_set_reg(dev, "btc_params", ++ (char *)®addr, (char *)&saved_reg68); ++ ++ AP6211_DEBUG("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", ++ saved_reg66, saved_reg41, saved_reg68); ++ } ++ saved_status = FALSE; ++ ++ } ++ else { ++ AP6211_ERR("%s Unkwown yet power setting, ignored\n", ++ __FUNCTION__); ++ } ++ ++ snprintf(command, 3, "OK"); ++ ++ return (strlen("OK")); ++} +diff --git a/drivers/net/wireless/ap6211/dhd_cfg80211.h b/drivers/net/wireless/ap6211/dhd_cfg80211.h +new file mode 100755 +index 0000000..922d6ed +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_cfg80211.h +@@ -0,0 +1,44 @@ ++/* ++ * Linux cfg80211 driver - Dongle Host Driver (DHD) related ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ ++ */ ++ ++ ++#ifndef __DHD_CFG80211__ ++#define __DHD_CFG80211__ ++ ++#include ++#include ++ ++s32 dhd_cfg80211_init(struct wl_priv *wl); ++s32 dhd_cfg80211_deinit(struct wl_priv *wl); ++s32 dhd_cfg80211_down(struct wl_priv *wl); ++s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val); ++s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl); ++s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock); ++ ++int wl_cfg80211_btcoex_init(struct wl_priv *wl); ++void wl_cfg80211_btcoex_deinit(struct wl_priv *wl); ++ ++#endif /* __DHD_CFG80211__ */ +diff --git a/drivers/net/wireless/ap6211/dhd_common.c b/drivers/net/wireless/ap6211/dhd_common.c +new file mode 100755 +index 0000000..96c021f +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_common.c +@@ -0,0 +1,2255 @@ ++/* ++ * Broadcom Dongle Host Driver (DHD), common DHD core. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_common.c 373873 2012-12-10 20:45:58Z $ ++ */ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#ifdef WL_CFG80211 ++#include ++#endif ++#ifdef WLBTAMP ++#include ++#include ++#endif ++#ifdef SET_RANDOM_MAC_SOFTAP ++#include ++#include ++#endif ++ ++#define htod32(i) i ++#define htod16(i) i ++#define dtoh32(i) i ++#define dtoh16(i) i ++#define htodchanspec(i) i ++#define dtohchanspec(i) i ++ ++#ifdef PROP_TXSTATUS ++#include ++#include ++#endif ++ ++#include ++#include ++ ++#ifdef WLMEDIA_HTSF ++extern void htsf_update(struct dhd_info *dhd, void *data); ++#endif ++int dhd_msg_level = DHD_ERROR_VAL; ++ ++ ++#include ++ ++char fw_path[MOD_PARAM_PATHLEN]; ++char nv_path[MOD_PARAM_PATHLEN]; ++ ++#ifdef SOFTAP ++char fw_path2[MOD_PARAM_PATHLEN]; ++extern bool softap_enabled; ++#endif ++ ++/* Last connection success/failure status */ ++uint32 dhd_conn_event; ++uint32 dhd_conn_status; ++uint32 dhd_conn_reason; ++ ++extern int dhd_iscan_request(void * dhdp, uint16 action); ++extern void dhd_ind_scan_confirm(void *h, bool status); ++extern int dhd_iscan_in_progress(void *h); ++void dhd_iscan_lock(void); ++void dhd_iscan_unlock(void); ++extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); ++#if !defined(AP) && defined(WLP2P) ++extern int dhd_get_concurrent_capabilites(dhd_pub_t *dhd); ++#endif ++bool ap_cfg_running = FALSE; ++bool ap_fw_loaded = FALSE; ++ ++ ++#ifdef DHD_DEBUG ++const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on " ++ __DATE__ " at " __TIME__; ++#else ++const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR; ++#endif ++ ++void dhd_set_timer(void *bus, uint wdtick); ++ ++/* IOVar table */ ++enum { ++ IOV_VERSION = 1, ++ IOV_WLMSGLEVEL, ++ IOV_MSGLEVEL, ++ IOV_BCMERRORSTR, ++ IOV_BCMERROR, ++ IOV_WDTICK, ++ IOV_DUMP, ++ IOV_CLEARCOUNTS, ++ IOV_LOGDUMP, ++ IOV_LOGCAL, ++ IOV_LOGSTAMP, ++ IOV_GPIOOB, ++ IOV_IOCTLTIMEOUT, ++#ifdef WLBTAMP ++ IOV_HCI_CMD, /* HCI command */ ++ IOV_HCI_ACL_DATA, /* HCI data packet */ ++#endif ++#if defined(DHD_DEBUG) ++ IOV_CONS, ++ IOV_DCONSOLE_POLL, ++#endif /* defined(DHD_DEBUG) */ ++#ifdef PROP_TXSTATUS ++ IOV_PROPTXSTATUS_ENABLE, ++ IOV_PROPTXSTATUS_MODE, ++#endif ++ IOV_BUS_TYPE, ++#ifdef WLMEDIA_HTSF ++ IOV_WLPKTDLYSTAT_SZ, ++#endif ++ IOV_CHANGEMTU, ++ IOV_HOSTREORDER_FLOWS, ++ IOV_LAST ++}; ++ ++const bcm_iovar_t dhd_iovars[] = { ++ {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) }, ++ {"wlmsglevel", IOV_WLMSGLEVEL, 0, IOVT_UINT32, 0 }, ++#ifdef DHD_DEBUG ++ {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, ++#endif /* DHD_DEBUG */ ++ {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN }, ++ {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 }, ++ {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 }, ++ {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, ++#ifdef DHD_DEBUG ++ {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 }, ++ {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 }, ++#endif ++ {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 }, ++ {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 }, ++ {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 }, ++#ifdef WLBTAMP ++ {"HCI_cmd", IOV_HCI_CMD, 0, IOVT_BUFFER, 0}, ++ {"HCI_ACL_data", IOV_HCI_ACL_DATA, 0, IOVT_BUFFER, 0}, ++#endif ++#ifdef PROP_TXSTATUS ++ {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, IOVT_UINT32, 0 }, ++ /* ++ set the proptxtstatus operation mode: ++ 0 - Do not do any proptxtstatus flow control ++ 1 - Use implied credit from a packet status ++ 2 - Use explicit credit ++ */ ++ {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, IOVT_UINT32, 0 }, ++#endif ++ {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0}, ++#ifdef WLMEDIA_HTSF ++ {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 }, ++#endif ++ {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 }, ++ {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, IOVT_BUFFER, ++ (WLHOST_REORDERDATA_MAXFLOWS + 1) }, ++ {NULL, 0, 0, 0, 0 } ++}; ++ ++void ++dhd_common_init(osl_t *osh) ++{ ++ int select_type = 0; ++ //aw checkout which wifi had select ++ select_type = ap6211_gpio_wifi_get_mod_type(); ++ ++#ifdef CONFIG_AP6211_FW_PATH ++ //select bcm40181/ap6181/ap6211 ++ if (select_type == 1 || select_type == 7 || select_type == 9) { ++ bcm_strncpy_s(fw_path, sizeof(fw_path), "/lib/firmware/ap6210/fw_bcm40181a2.bin", MOD_PARAM_PATHLEN-1); ++ } ++ //select bcm40183 ++ if (select_type == 2) { ++ bcm_strncpy_s(fw_path, sizeof(fw_path), "/lib/firmware/ap6211/fw_bcm40183b2.bin", MOD_PARAM_PATHLEN-1); ++ } ++ //select ap6330 ++ if (select_type == 8) { ++ bcm_strncpy_s(fw_path, sizeof(fw_path), "/lib/firmware/ap6211/fw_bcm40183b2_ag.bin", MOD_PARAM_PATHLEN-1); ++ } ++ ++#else /* CONFIG_AP6211_FW_PATH */ ++ fw_path[0] = '\0'; ++#endif /* CONFIG_AP6211_FW_PATH */ ++#ifdef CONFIG_AP6211_NVRAM_PATH ++ //select bcm40181 ++ if (select_type == 1) { ++ bcm_strncpy_s(nv_path, sizeof(nv_path), "/lib/firmware/ap6210/nvram_bcm40181.txt", MOD_PARAM_PATHLEN-1); ++ } ++ //select bcm40183 ++ if (select_type == 2) { ++ bcm_strncpy_s(nv_path, sizeof(nv_path), "/lib/firmware/ap6210/nvram_bcm40183.txt", MOD_PARAM_PATHLEN-1); ++ } ++ //select ap6211 ++ if (select_type == 7) { ++ bcm_strncpy_s(nv_path, sizeof(nv_path), "/lib/firmware/ap6210/nvram_ap6210.txt", MOD_PARAM_PATHLEN-1); ++ } ++ ++ //select ap6330 ++ if (select_type == 8) { ++ bcm_strncpy_s(nv_path, sizeof(nv_path), "/lib/firmware/ap6210/nvram_ap6330.txt", MOD_PARAM_PATHLEN-1); ++ } ++ //select ap6181 ++ if (select_type == 9) { ++ bcm_strncpy_s(nv_path, sizeof(nv_path), "/lib/firmware/ap6210/nvram_ap6181.txt", MOD_PARAM_PATHLEN-1); ++ } ++#else /* CONFIG_AP6211_NVRAM_PATH */ ++ nv_path[0] = '\0'; ++#endif /* CONFIG_AP6211_NVRAM_PATH */ ++#ifdef SOFTAP ++ fw_path2[0] = '\0'; ++#endif ++} ++ ++static int ++dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) ++{ ++ char eabuf[ETHER_ADDR_STR_LEN]; ++ ++ struct bcmstrbuf b; ++ struct bcmstrbuf *strbuf = &b; ++ ++ bcm_binit(strbuf, buf, buflen); ++ ++ /* Base DHD info */ ++ bcm_bprintf(strbuf, "%s\n", dhd_version); ++ bcm_bprintf(strbuf, "\n"); ++ bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n", ++ dhdp->up, dhdp->txoff, dhdp->busstate); ++ bcm_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n", ++ dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz); ++ bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n", ++ dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf)); ++ bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", dhdp->bcmerror, dhdp->tickcnt); ++ ++ bcm_bprintf(strbuf, "dongle stats:\n"); ++ bcm_bprintf(strbuf, "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n", ++ dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes, ++ dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped); ++ bcm_bprintf(strbuf, "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n", ++ dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes, ++ dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped); ++ bcm_bprintf(strbuf, "multicast %ld\n", dhdp->dstats.multicast); ++ ++ bcm_bprintf(strbuf, "bus stats:\n"); ++ bcm_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n", ++ dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors); ++ bcm_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n", ++ dhdp->tx_ctlpkts, dhdp->tx_ctlerrs); ++ bcm_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld \n", ++ dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors); ++ bcm_bprintf(strbuf, "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld\n", ++ dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped); ++ bcm_bprintf(strbuf, "rx_readahead_cnt %ld tx_realloc %ld\n", ++ dhdp->rx_readahead_cnt, dhdp->tx_realloc); ++ bcm_bprintf(strbuf, "\n"); ++ ++ /* Add any prot info */ ++ dhd_prot_dump(dhdp, strbuf); ++ bcm_bprintf(strbuf, "\n"); ++ ++ /* Add any bus info */ ++ dhd_bus_dump(dhdp, strbuf); ++ ++ return (!strbuf->size ? BCME_BUFTOOSHORT : 0); ++} ++ ++int ++dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifindex) ++{ ++ wl_ioctl_t ioc; ++ ++ ioc.cmd = cmd; ++ ioc.buf = arg; ++ ioc.len = len; ++ ioc.set = set; ++ ++ return dhd_wl_ioctl(dhd_pub, ifindex, &ioc, arg, len); ++} ++ ++ ++int ++dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len) ++{ ++ int ret; ++ ++ dhd_os_proto_block(dhd_pub); ++ ++ ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len); ++ if ((ret) && (dhd_pub->up)) ++ /* Send hang event only if dhd_open() was success */ ++ dhd_os_check_hang(dhd_pub, ifindex, ret); ++ ++ dhd_os_proto_unblock(dhd_pub); ++ ++ return ret; ++} ++ ++static int ++dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name, ++ void *params, int plen, void *arg, int len, int val_size) ++{ ++ int bcmerror = 0; ++ int32 int_val = 0; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ AP6211_DEBUG("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name); ++ ++ if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) ++ goto exit; ++ ++ if (plen >= (int)sizeof(int_val)) ++ bcopy(params, &int_val, sizeof(int_val)); ++ ++ switch (actionid) { ++ case IOV_GVAL(IOV_VERSION): ++ /* Need to have checked buffer length */ ++ bcm_strncpy_s((char*)arg, len, dhd_version, len); ++ break; ++ ++ case IOV_GVAL(IOV_WLMSGLEVEL): ++ //AP6211_DEBUG("android_msg_level=0x%x\n", android_msg_level); ++#if defined(CONFIG_WIRELESS_EXT) ++ int_val = (int32)iw_msg_level; ++ bcopy(&int_val, arg, val_size); ++ AP6211_DEBUG("iw_msg_level=0x%x\n", iw_msg_level); ++#endif ++#ifdef WL_CFG80211 ++ int_val = (int32)wl_dbg_level; ++ bcopy(&int_val, arg, val_size); ++ AP6211_DEBUG("cfg_msg_level=0x%x\n", wl_dbg_level); ++#endif ++ break; ++ ++ case IOV_SVAL(IOV_WLMSGLEVEL): ++#if defined(CONFIG_WIRELESS_EXT) ++ if (int_val & DHD_IW_VAL) { ++ iw_msg_level = (uint)(int_val & 0xFFFF); ++ AP6211_DEBUG("iw_msg_level=0x%x\n", iw_msg_level); ++ } else ++#endif ++#ifdef WL_CFG80211 ++ if (int_val & DHD_CFG_VAL) { ++ wl_cfg80211_enable_trace((u32)(int_val & 0xFFFF)); ++ } else ++#endif ++ { ++ //android_msg_level = (uint)int_val; ++ //AP6211_DEBUG("android_msg_level=0x%x\n", android_msg_level); ++ } ++ break; ++ ++ case IOV_GVAL(IOV_MSGLEVEL): ++ int_val = (int32)dhd_msg_level; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_MSGLEVEL): ++ dhd_msg_level = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_BCMERRORSTR): ++ bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); ++ ((char *)arg)[BCME_STRLEN - 1] = 0x00; ++ break; ++ ++ case IOV_GVAL(IOV_BCMERROR): ++ int_val = (int32)dhd_pub->bcmerror; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_WDTICK): ++ int_val = (int32)dhd_watchdog_ms; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_WDTICK): ++ if (!dhd_pub->up) { ++ bcmerror = BCME_NOTUP; ++ break; ++ } ++ dhd_os_wd_timer(dhd_pub, (uint)int_val); ++ break; ++ ++ case IOV_GVAL(IOV_DUMP): ++ bcmerror = dhd_dump(dhd_pub, arg, len); ++ break; ++ ++#ifdef DHD_DEBUG ++ case IOV_GVAL(IOV_DCONSOLE_POLL): ++ int_val = (int32)dhd_console_ms; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DCONSOLE_POLL): ++ dhd_console_ms = (uint)int_val; ++ break; ++ ++ case IOV_SVAL(IOV_CONS): ++ if (len > 0) ++ bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1); ++ break; ++#endif /* DHD_DEBUG */ ++ ++ case IOV_SVAL(IOV_CLEARCOUNTS): ++ dhd_pub->tx_packets = dhd_pub->rx_packets = 0; ++ dhd_pub->tx_errors = dhd_pub->rx_errors = 0; ++ dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0; ++ dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0; ++ dhd_pub->rx_dropped = 0; ++ dhd_pub->rx_readahead_cnt = 0; ++ dhd_pub->tx_realloc = 0; ++ dhd_pub->wd_dpc_sched = 0; ++ memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats)); ++ dhd_bus_clearcounts(dhd_pub); ++#ifdef PROP_TXSTATUS ++ /* clear proptxstatus related counters */ ++ if (dhd_pub->wlfc_state) { ++ athost_wl_status_info_t *wlfc = ++ (athost_wl_status_info_t*)dhd_pub->wlfc_state; ++ wlfc_hanger_t* hanger; ++ ++ memset(&wlfc->stats, 0, sizeof(athost_wl_stat_counters_t)); ++ ++ hanger = (wlfc_hanger_t*)wlfc->hanger; ++ hanger->pushed = 0; ++ hanger->popped = 0; ++ hanger->failed_slotfind = 0; ++ hanger->failed_to_pop = 0; ++ hanger->failed_to_push = 0; ++ } ++#endif /* PROP_TXSTATUS */ ++ break; ++ ++ ++ case IOV_GVAL(IOV_IOCTLTIMEOUT): { ++ int_val = (int32)dhd_os_get_ioctl_resp_timeout(); ++ bcopy(&int_val, arg, sizeof(int_val)); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_IOCTLTIMEOUT): { ++ if (int_val <= 0) ++ bcmerror = BCME_BADARG; ++ else ++ dhd_os_set_ioctl_resp_timeout((unsigned int)int_val); ++ break; ++ } ++ ++#ifdef WLBTAMP ++ case IOV_SVAL(IOV_HCI_CMD): { ++ amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)arg; ++ ++ /* sanity check: command preamble present */ ++ if (len < HCI_CMD_PREAMBLE_SIZE) ++ return BCME_BUFTOOSHORT; ++ ++ /* sanity check: command parameters are present */ ++ if (len < (int)(HCI_CMD_PREAMBLE_SIZE + cmd->plen)) ++ return BCME_BUFTOOSHORT; ++ ++ dhd_bta_docmd(dhd_pub, cmd, len); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_HCI_ACL_DATA): { ++ amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)arg; ++ ++ /* sanity check: HCI header present */ ++ if (len < HCI_ACL_DATA_PREAMBLE_SIZE) ++ return BCME_BUFTOOSHORT; ++ ++ /* sanity check: ACL data is present */ ++ if (len < (int)(HCI_ACL_DATA_PREAMBLE_SIZE + ACL_data->dlen)) ++ return BCME_BUFTOOSHORT; ++ ++ dhd_bta_tx_hcidata(dhd_pub, ACL_data, len); ++ break; ++ } ++#endif /* WLBTAMP */ ++ ++#ifdef PROP_TXSTATUS ++ case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): ++ int_val = dhd_pub->wlfc_enabled? 1 : 0; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE): ++ dhd_pub->wlfc_enabled = int_val? 1 : 0; ++ break; ++ ++ case IOV_GVAL(IOV_PROPTXSTATUS_MODE): { ++ athost_wl_status_info_t *wlfc = ++ (athost_wl_status_info_t*)dhd_pub->wlfc_state; ++ int_val = dhd_pub->wlfc_state ? (int32)wlfc->proptxstatus_mode : 0; ++ bcopy(&int_val, arg, val_size); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_PROPTXSTATUS_MODE): ++ if (dhd_pub->wlfc_state) { ++ athost_wl_status_info_t *wlfc = ++ (athost_wl_status_info_t*)dhd_pub->wlfc_state; ++ wlfc->proptxstatus_mode = int_val & 0xff; ++ } ++ break; ++#endif /* PROP_TXSTATUS */ ++ ++ case IOV_GVAL(IOV_BUS_TYPE): ++ /* The dhd application queries the driver to check if its usb or sdio. */ ++#ifdef AP6211USB ++ int_val = BUS_TYPE_USB; ++#endif ++ int_val = BUS_TYPE_SDIO; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ ++#ifdef WLMEDIA_HTSF ++ case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ): ++ int_val = dhd_pub->htsfdlystat_sz; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ): ++ dhd_pub->htsfdlystat_sz = int_val & 0xff; ++ AP6211_DEBUG("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz); ++ break; ++#endif ++ case IOV_SVAL(IOV_CHANGEMTU): ++ int_val &= 0xffff; ++ bcmerror = dhd_change_mtu(dhd_pub, int_val, 0); ++ break; ++ ++ case IOV_GVAL(IOV_HOSTREORDER_FLOWS): ++ { ++ uint i = 0; ++ uint8 *ptr = (uint8 *)arg; ++ uint8 count = 0; ++ ++ ptr++; ++ for (i = 0; i < WLHOST_REORDERDATA_MAXFLOWS; i++) { ++ if (dhd_pub->reorder_bufs[i] != NULL) { ++ *ptr = dhd_pub->reorder_bufs[i]->flow_id; ++ ptr++; ++ count++; ++ } ++ } ++ ptr = (uint8 *)arg; ++ *ptr = count; ++ break; ++ } ++ ++ default: ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++ ++exit: ++ AP6211_DEBUG("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror); ++ return bcmerror; ++} ++ ++/* Store the status of a connection attempt for later retrieval by an iovar */ ++void ++dhd_store_conn_status(uint32 event, uint32 status, uint32 reason) ++{ ++ /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID ++ * because an encryption/rsn mismatch results in both events, and ++ * the important information is in the WLC_E_PRUNE. ++ */ ++ if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL && ++ dhd_conn_event == WLC_E_PRUNE)) { ++ dhd_conn_event = event; ++ dhd_conn_status = status; ++ dhd_conn_reason = reason; ++ } ++} ++ ++bool ++dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) ++{ ++ void *p; ++ int eprec = -1; /* precedence to evict from */ ++ bool discard_oldest; ++ ++ /* Fast case, precedence queue is not full and we are also not ++ * exceeding total queue length ++ */ ++ if (!pktq_pfull(q, prec) && !pktq_full(q)) { ++ pktq_penq(q, prec, pkt); ++ return TRUE; ++ } ++ ++ /* Determine precedence from which to evict packet, if any */ ++ if (pktq_pfull(q, prec)) ++ eprec = prec; ++ else if (pktq_full(q)) { ++ pktq_peek_tail(q, &eprec); ++ if (eprec > prec || eprec < 0) ++ return FALSE; ++ } ++ ++ /* Evict if needed */ ++ if (eprec >= 0) { ++ /* Detect queueing to unconfigured precedence */ ++ ASSERT(!pktq_pempty(q, eprec)); ++ discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec); ++ if (eprec == prec && !discard_oldest) ++ return FALSE; /* refuse newer (incoming) packet */ ++ /* Evict packet according to discard policy */ ++ p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec); ++ ASSERT(p); ++ ++ PKTFREE(dhdp->osh, p, TRUE); ++ } ++ ++ /* Enqueue */ ++ pktq_penq(q, prec, pkt); ++ ++ return TRUE; ++} ++ ++static int ++dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ int bcmerror = 0; ++ int val_size; ++ const bcm_iovar_t *vi = NULL; ++ uint32 actionid; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ ASSERT(name); ++ ASSERT(len >= 0); ++ ++ /* Get MUST have return space */ ++ ASSERT(set || (arg && len)); ++ ++ /* Set does NOT take qualifiers */ ++ ASSERT(!set || (!params && !plen)); ++ ++ if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) { ++ bcmerror = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ ++ AP6211_DEBUG("%s: %s %s, len %d plen %d\n", __FUNCTION__, ++ name, (set ? "set" : "get"), len, plen); ++ ++ /* set up 'params' pointer in case this is a set command so that ++ * the convenience int and bool code can be common to set and get ++ */ ++ if (params == NULL) { ++ params = arg; ++ plen = len; ++ } ++ ++ if (vi->type == IOVT_VOID) ++ val_size = 0; ++ else if (vi->type == IOVT_BUFFER) ++ val_size = len; ++ else ++ /* all other types are integer sized */ ++ val_size = sizeof(int); ++ ++ actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); ++ ++ bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size); ++ ++exit: ++ return bcmerror; ++} ++ ++int ++dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen) ++{ ++ int bcmerror = 0; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (!buf) { ++ return BCME_BADARG; ++ } ++ ++ switch (ioc->cmd) { ++ case DHD_GET_MAGIC: ++ if (buflen < sizeof(int)) ++ bcmerror = BCME_BUFTOOSHORT; ++ else ++ *(int*)buf = DHD_IOCTL_MAGIC; ++ break; ++ ++ case DHD_GET_VERSION: ++ if (buflen < sizeof(int)) ++ bcmerror = -BCME_BUFTOOSHORT; ++ else ++ *(int*)buf = DHD_IOCTL_VERSION; ++ break; ++ ++ case DHD_GET_VAR: ++ case DHD_SET_VAR: { ++ char *arg; ++ uint arglen; ++ ++ /* scan past the name to any arguments */ ++ for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--) ++ ; ++ ++ if (*arg) { ++ bcmerror = BCME_BUFTOOSHORT; ++ break; ++ } ++ ++ /* account for the NUL terminator */ ++ arg++, arglen--; ++ ++ /* call with the appropriate arguments */ ++ if (ioc->cmd == DHD_GET_VAR) ++ bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen, ++ buf, buflen, IOV_GET); ++ else ++ bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET); ++ if (bcmerror != BCME_UNSUPPORTED) ++ break; ++ ++ /* not in generic table, try protocol module */ ++ if (ioc->cmd == DHD_GET_VAR) ++ bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg, ++ arglen, buf, buflen, IOV_GET); ++ else ++ bcmerror = dhd_prot_iovar_op(dhd_pub, buf, ++ NULL, 0, arg, arglen, IOV_SET); ++ if (bcmerror != BCME_UNSUPPORTED) ++ break; ++ ++ /* if still not found, try bus module */ ++ if (ioc->cmd == DHD_GET_VAR) { ++ bcmerror = dhd_bus_iovar_op(dhd_pub, buf, ++ arg, arglen, buf, buflen, IOV_GET); ++ } else { ++ bcmerror = dhd_bus_iovar_op(dhd_pub, buf, ++ NULL, 0, arg, arglen, IOV_SET); ++ } ++ ++ break; ++ } ++ ++ default: ++ bcmerror = BCME_UNSUPPORTED; ++ } ++ ++ return bcmerror; ++} ++ ++#ifdef SHOW_EVENTS ++static void ++wl_show_host_event(wl_event_msg_t *event, void *event_data) ++{ ++ uint i, status, reason; ++ bool group = FALSE, flush_txq = FALSE, link = FALSE; ++ const char *auth_str; ++ const char *event_name; ++ uchar *buf; ++ char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; ++ uint event_type, flags, auth_type, datalen; ++ ++ event_type = ntoh32(event->event_type); ++ flags = ntoh16(event->flags); ++ status = ntoh32(event->status); ++ reason = ntoh32(event->reason); ++ BCM_REFERENCE(reason); ++ auth_type = ntoh32(event->auth_type); ++ datalen = ntoh32(event->datalen); ++ ++ /* debug dump of event messages */ ++ snprintf(eabuf, sizeof(eabuf), "%02x:%02x:%02x:%02x:%02x:%02x", ++ (uchar)event->addr.octet[0]&0xff, ++ (uchar)event->addr.octet[1]&0xff, ++ (uchar)event->addr.octet[2]&0xff, ++ (uchar)event->addr.octet[3]&0xff, ++ (uchar)event->addr.octet[4]&0xff, ++ (uchar)event->addr.octet[5]&0xff); ++ ++ event_name = "UNKNOWN"; ++ for (i = 0; i < (uint)bcmevent_names_size; i++) ++ if (bcmevent_names[i].event == event_type) ++ event_name = bcmevent_names[i].name; ++ ++ if (flags & WLC_EVENT_MSG_LINK) ++ link = TRUE; ++ if (flags & WLC_EVENT_MSG_GROUP) ++ group = TRUE; ++ if (flags & WLC_EVENT_MSG_FLUSHTXQ) ++ flush_txq = TRUE; ++ ++ switch (event_type) { ++ case WLC_E_START: ++ case WLC_E_DEAUTH: ++ case WLC_E_DISASSOC: ++ AP6211_DEBUG("MACEVENT: %s, MAC %s\n", event_name, eabuf); ++ break; ++ ++ case WLC_E_ASSOC_IND: ++ case WLC_E_REASSOC_IND: ++ ++ AP6211_DEBUG("MACEVENT: %s, MAC %s\n", event_name, eabuf); ++ break; ++ ++ case WLC_E_ASSOC: ++ case WLC_E_REASSOC: ++ if (status == WLC_E_STATUS_SUCCESS) { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf); ++ } else if (status == WLC_E_STATUS_TIMEOUT) { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf); ++ } else if (status == WLC_E_STATUS_FAIL) { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, FAILURE, reason %d\n", ++ event_name, eabuf, (int)reason); ++ } else { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, unexpected status %d\n", ++ event_name, eabuf, (int)status); ++ } ++ break; ++ ++ case WLC_E_DEAUTH_IND: ++ case WLC_E_DISASSOC_IND: ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason); ++ break; ++ ++ case WLC_E_AUTH: ++ case WLC_E_AUTH_IND: ++ if (auth_type == DOT11_OPEN_SYSTEM) ++ auth_str = "Open System"; ++ else if (auth_type == DOT11_SHARED_KEY) ++ auth_str = "Shared Key"; ++ else { ++ snprintf(err_msg, sizeof(err_msg), "AUTH unknown: %d", (int)auth_type); ++ auth_str = err_msg; ++ } ++ if (event_type == WLC_E_AUTH_IND) { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str); ++ } else if (status == WLC_E_STATUS_SUCCESS) { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, %s, SUCCESS\n", ++ event_name, eabuf, auth_str); ++ } else if (status == WLC_E_STATUS_TIMEOUT) { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, %s, TIMEOUT\n", ++ event_name, eabuf, auth_str); ++ } else if (status == WLC_E_STATUS_FAIL) { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n", ++ event_name, eabuf, auth_str, (int)reason); ++ } ++ BCM_REFERENCE(auth_str); ++ ++ break; ++ ++ case WLC_E_JOIN: ++ case WLC_E_ROAM: ++ case WLC_E_SET_SSID: ++ if (status == WLC_E_STATUS_SUCCESS) { ++ AP6211_DEBUG("MACEVENT: %s, MAC %s\n", event_name, eabuf); ++ } else if (status == WLC_E_STATUS_FAIL) { ++ AP6211_DEBUG("MACEVENT: %s, failed\n", event_name); ++ } else if (status == WLC_E_STATUS_NO_NETWORKS) { ++ AP6211_DEBUG("MACEVENT: %s, no networks found\n", event_name); ++ } else { ++ AP6211_DEBUG("MACEVENT: %s, unexpected status %d\n", ++ event_name, (int)status); ++ } ++ break; ++ ++ case WLC_E_BEACON_RX: ++ if (status == WLC_E_STATUS_SUCCESS) { ++ AP6211_DEBUG("MACEVENT: %s, SUCCESS\n", event_name); ++ } else if (status == WLC_E_STATUS_FAIL) { ++ AP6211_DEBUG("MACEVENT: %s, FAIL\n", event_name); ++ } else { ++ AP6211_DEBUG("MACEVENT: %s, status %d\n", event_name, status); ++ } ++ break; ++ ++ case WLC_E_LINK: ++ AP6211_DEBUG("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN"); ++ BCM_REFERENCE(link); ++ break; ++ ++ case WLC_E_MIC_ERROR: ++ AP6211_DEBUG("MACEVENT: %s, MAC %s, Group %d, Flush %d\n", ++ event_name, eabuf, group, flush_txq); ++ BCM_REFERENCE(group); ++ BCM_REFERENCE(flush_txq); ++ break; ++ ++ case WLC_E_ICV_ERROR: ++ case WLC_E_UNICAST_DECODE_ERROR: ++ case WLC_E_MULTICAST_DECODE_ERROR: ++ AP6211_DEBUG("MACEVENT: %s, MAC %s\n", ++ event_name, eabuf); ++ break; ++ ++ case WLC_E_TXFAIL: ++ AP6211_DEBUG("MACEVENT: %s, RA %s\n", event_name, eabuf); ++ break; ++ ++ case WLC_E_SCAN_COMPLETE: ++ case WLC_E_ASSOC_REQ_IE: ++ case WLC_E_ASSOC_RESP_IE: ++ case WLC_E_PMKID_CACHE: ++ AP6211_DEBUG("MACEVENT: %s\n", event_name); ++ break; ++ ++ case WLC_E_PFN_NET_FOUND: ++ case WLC_E_PFN_NET_LOST: ++ case WLC_E_PFN_SCAN_COMPLETE: ++ case WLC_E_PFN_SCAN_NONE: ++ case WLC_E_PFN_SCAN_ALLGONE: ++ AP6211_DEBUG("PNOEVENT: %s\n", event_name); ++ break; ++ ++ case WLC_E_PSK_SUP: ++ case WLC_E_PRUNE: ++ AP6211_DEBUG("MACEVENT: %s, status %d, reason %d\n", ++ event_name, (int)status, (int)reason); ++ break; ++ ++#ifdef WIFI_ACT_FRAME ++ case WLC_E_ACTION_FRAME: ++ AP6211_DEBUG("MACEVENT: %s Bssid %s\n", event_name, eabuf); ++ break; ++#endif /* WIFI_ACT_FRAME */ ++ ++ case WLC_E_TRACE: { ++ static uint32 seqnum_prev = 0; ++ msgtrace_hdr_t hdr; ++ uint32 nblost; ++ char *s, *p; ++ ++ buf = (uchar *) event_data; ++ memcpy(&hdr, buf, MSGTRACE_HDRLEN); ++ ++ if (hdr.version != MSGTRACE_VERSION) { ++ AP6211_DEBUG("MACEVENT: %s [unsupported version --> " ++ "dhd version:%d dongle version:%d]\n", ++ event_name, MSGTRACE_VERSION, hdr.version); ++ /* Reset datalen to avoid display below */ ++ datalen = 0; ++ break; ++ } ++ ++ /* There are 2 bytes available at the end of data */ ++ buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0'; ++ ++ if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) { ++ AP6211_DEBUG("WLC_E_TRACE: [Discarded traces in dongle -->" ++ "discarded_bytes %d discarded_printf %d]\n", ++ ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf)); ++ } ++ ++ nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1; ++ if (nblost > 0) { ++ AP6211_DEBUG("WLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n", ++ ntoh32(hdr.seqnum), nblost); ++ } ++ seqnum_prev = ntoh32(hdr.seqnum); ++ ++ /* Display the trace buffer. Advance from \n to \n to avoid display big ++ * printf (issue with Linux printk ) ++ */ ++ p = (char *)&buf[MSGTRACE_HDRLEN]; ++ while ((s = strstr(p, "\n")) != NULL) { ++ *s = '\0'; ++ AP6211_DEBUG("%s\n", p); ++ p = s+1; ++ } ++ AP6211_DEBUG("%s\n", p); ++ ++ /* Reset datalen to avoid display below */ ++ datalen = 0; ++ break; ++ } ++ ++ ++ case WLC_E_RSSI: ++ AP6211_DEBUG("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data))); ++ break; ++ ++ case WLC_E_SERVICE_FOUND: ++ case WLC_E_P2PO_ADD_DEVICE: ++ case WLC_E_P2PO_DEL_DEVICE: ++ AP6211_DEBUG("MACEVENT: %s, MAC: %s\n", event_name, eabuf); ++ break; ++ ++ default: ++ AP6211_DEBUG("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n", ++ event_name, event_type, eabuf, (int)status, (int)reason, ++ (int)auth_type); ++ break; ++ } ++ ++ /* show any appended data */ ++ if (datalen) { ++ buf = (uchar *) event_data; ++ AP6211_DEBUG(" data (%d) : ", datalen); ++ for (i = 0; i < datalen; i++) ++ AP6211_DUMP(" 0x%02x ", *buf++); ++ AP6211_DUMP("\n"); ++ } ++} ++#endif /* SHOW_EVENTS */ ++ ++int ++wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, ++ wl_event_msg_t *event, void **data_ptr) ++{ ++ /* check whether packet is a BRCM event pkt */ ++ bcm_event_t *pvt_data = (bcm_event_t *)pktdata; ++ uint8 *event_data; ++ uint32 type, status, datalen; ++ uint16 flags; ++ int evlen; ++ ++ if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) { ++ AP6211_ERR("%s: mismatched OUI, bailing\n", __FUNCTION__); ++ return (BCME_ERROR); ++ } ++ ++ /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */ ++ if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) { ++ AP6211_ERR("%s: mismatched subtype, bailing\n", __FUNCTION__); ++ return (BCME_ERROR); ++ } ++ ++ *data_ptr = &pvt_data[1]; ++ event_data = *data_ptr; ++ ++ /* memcpy since BRCM event pkt may be unaligned. */ ++ memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t)); ++ ++ type = ntoh32_ua((void *)&event->event_type); ++ flags = ntoh16_ua((void *)&event->flags); ++ status = ntoh32_ua((void *)&event->status); ++ datalen = ntoh32_ua((void *)&event->datalen); ++ evlen = datalen + sizeof(bcm_event_t); ++ ++ switch (type) { ++#ifdef PROP_TXSTATUS ++ case WLC_E_FIFO_CREDIT_MAP: ++ dhd_wlfc_event(dhd_pub->info); ++ dhd_wlfc_FIFOcreditmap_event(dhd_pub->info, event_data); ++ AP6211_DEBUG("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): " ++ "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1], ++ event_data[2], ++ event_data[3], event_data[4], event_data[5]); ++ break; ++#endif ++ ++ case WLC_E_IF: ++ { ++ dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data; ++#ifdef PROP_TXSTATUS ++ { ++ uint8* ea = pvt_data->eth.ether_dhost; ++ AP6211_DEBUG("WLC_E_IF: idx:%d, action:%s, iftype:%s, " ++ "[%02x:%02x:%02x:%02x:%02x:%02x]\n", ++ ifevent->ifidx, ++ ((ifevent->action == WLC_E_IF_ADD) ? "ADD":"DEL"), ++ ((ifevent->is_AP == 0) ? "STA":"AP "), ++ ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]); ++ (void)ea; ++ if (ifevent->action == WLC_E_IF_CHANGE) ++ dhd_wlfc_interface_event(dhd_pub->info, ++ eWLFC_MAC_ENTRY_ACTION_UPDATE, ++ ifevent->ifidx, ifevent->is_AP, ea); ++ else ++ dhd_wlfc_interface_event(dhd_pub->info, ++ ((ifevent->action == WLC_E_IF_ADD) ? ++ eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL), ++ ifevent->ifidx, ifevent->is_AP, ea); ++ ++ ++ /* dhd already has created an interface by default, for 0 */ ++ if (ifevent->ifidx == 0) ++ break; ++ } ++#endif /* PROP_TXSTATUS */ ++ ++#ifdef WL_CFG80211 ++ if (wl_cfg80211_is_progress_ifchange()) { ++ AP6211_ERR("%s: ifidx %d for %s action %d\n", ++ __FUNCTION__, ifevent->ifidx, ++ event->ifname, ifevent->action); ++ if (ifevent->action == WLC_E_IF_ADD || ++ ifevent->action == WLC_E_IF_CHANGE) ++ wl_cfg80211_notify_ifchange(); ++ return (BCME_OK); ++ } ++#endif /* WL_CFG80211 */ ++ if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) { ++ if (ifevent->action == WLC_E_IF_ADD) { ++ if (dhd_add_if(dhd_pub->info, ifevent->ifidx, ++ NULL, event->ifname, ++ event->addr.octet, ++ ifevent->flags, ifevent->bssidx)) { ++ AP6211_ERR("%s: dhd_add_if failed!!" ++ " ifidx: %d for %s\n", ++ __FUNCTION__, ++ ifevent->ifidx, ++ event->ifname); ++ return (BCME_ERROR); ++ } ++ } ++ else if (ifevent->action == WLC_E_IF_DEL) ++ dhd_del_if(dhd_pub->info, ifevent->ifidx); ++ } else { ++#ifndef PROP_TXSTATUS ++ AP6211_ERR("%s: Invalid ifidx %d for %s\n", ++ __FUNCTION__, ifevent->ifidx, event->ifname); ++#endif /* !PROP_TXSTATUS */ ++ } ++ } ++ /* send up the if event: btamp user needs it */ ++ *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); ++ /* push up to external supp/auth */ ++ dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); ++ break; ++ ++ ++#ifdef WLMEDIA_HTSF ++ case WLC_E_HTSFSYNC: ++ htsf_update(dhd_pub->info, event_data); ++ break; ++#endif /* WLMEDIA_HTSF */ ++#if defined(NDIS630) ++ case WLC_E_NDIS_LINK: ++ break; ++#else /* defined(NDIS630) && defined(BCMDONGLEHOST) */ ++ case WLC_E_NDIS_LINK: { ++ uint32 temp = hton32(WLC_E_LINK); ++ ++ memcpy((void *)(&pvt_data->event.event_type), &temp, ++ sizeof(pvt_data->event.event_type)); ++ } ++#endif ++ /* These are what external supplicant/authenticator wants */ ++ /* fall through */ ++ case WLC_E_LINK: ++ case WLC_E_DEAUTH: ++ case WLC_E_DEAUTH_IND: ++ case WLC_E_DISASSOC: ++ case WLC_E_DISASSOC_IND: ++ AP6211_DEBUG("%s: Link event %d, flags %x, status %x\n", ++ __FUNCTION__, type, flags, status); ++ /* fall through */ ++ default: ++ *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); ++ /* push up to external supp/auth */ ++ dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); ++ AP6211_DEBUG("%s: MAC event %d, flags %x, status %x\n", ++ __FUNCTION__, type, flags, status); ++ BCM_REFERENCE(flags); ++ BCM_REFERENCE(status); ++ ++ /* put it back to WLC_E_NDIS_LINK */ ++ if (type == WLC_E_NDIS_LINK) { ++ uint32 temp; ++ ++ temp = ntoh32_ua((void *)&event->event_type); ++ AP6211_DEBUG("Converted to WLC_E_LINK type %d\n", temp); ++ ++ temp = ntoh32(WLC_E_NDIS_LINK); ++ memcpy((void *)(&pvt_data->event.event_type), &temp, ++ sizeof(pvt_data->event.event_type)); ++ } ++ break; ++ } ++ ++#ifdef SHOW_EVENTS ++ wl_show_host_event(event, (void *)event_data); ++#endif /* SHOW_EVENTS */ ++ ++ return (BCME_OK); ++} ++ ++void ++wl_event_to_host_order(wl_event_msg_t * evt) ++{ ++ /* Event struct members passed from dongle to host are stored in network ++ * byte order. Convert all members to host-order. ++ */ ++ evt->event_type = ntoh32(evt->event_type); ++ evt->flags = ntoh16(evt->flags); ++ evt->status = ntoh32(evt->status); ++ evt->reason = ntoh32(evt->reason); ++ evt->auth_type = ntoh32(evt->auth_type); ++ evt->datalen = ntoh32(evt->datalen); ++ evt->version = ntoh16(evt->version); ++} ++ ++void ++dhd_print_buf(void *pbuf, int len, int bytes_per_line) ++{ ++#ifdef DHD_DEBUG ++ int i, j = 0; ++ unsigned char *buf = pbuf; ++ ++ if (bytes_per_line == 0) { ++ bytes_per_line = len; ++ } ++ ++ for (i = 0; i < len; i++) { ++ AP6211_DUMP("%2.2x", *buf++); ++ j++; ++ if (j == bytes_per_line) { ++ AP6211_DUMP("\n"); ++ j = 0; ++ } else { ++ AP6211_DUMP(":"); ++ } ++ } ++ AP6211_DUMP("\n"); ++#endif /* DHD_DEBUG */ ++} ++ ++#ifndef strtoul ++#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) ++#endif ++ ++#ifdef PKT_FILTER_SUPPORT ++/* Convert user's input in hex pattern to byte-size mask */ ++static int ++wl_pattern_atoh(char *src, char *dst) ++{ ++ int i; ++ if (strncmp(src, "0x", 2) != 0 && ++ strncmp(src, "0X", 2) != 0) { ++ AP6211_ERR("Mask invalid format. Needs to start with 0x\n"); ++ return -1; ++ } ++ src = src + 2; /* Skip past 0x */ ++ if (strlen(src) % 2 != 0) { ++ AP6211_ERR("Mask invalid format. Needs to be of even length\n"); ++ return -1; ++ } ++ for (i = 0; *src != '\0'; i++) { ++ char num[3]; ++ bcm_strncpy_s(num, sizeof(num), src, 2); ++ num[2] = '\0'; ++ dst[i] = (uint8)strtoul(num, NULL, 16); ++ src += 2; ++ } ++ return i; ++} ++ ++void ++dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode) ++{ ++ char *argv[8]; ++ int i = 0; ++ const char *str; ++ int buf_len; ++ int str_len; ++ char *arg_save = 0, *arg_org = 0; ++ int rc; ++ char buf[128]; ++ wl_pkt_filter_enable_t enable_parm; ++ wl_pkt_filter_enable_t * pkt_filterp; ++ ++ if (!arg) ++ return; ++ ++ if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { ++ AP6211_ERR("%s: kmalloc failed\n", __FUNCTION__); ++ goto fail; ++ } ++ arg_org = arg_save; ++ memcpy(arg_save, arg, strlen(arg) + 1); ++ ++ argv[i] = bcmstrtok(&arg_save, " ", 0); ++ ++ i = 0; ++ if (argv[i] == NULL) { ++ AP6211_ERR("No args provided\n"); ++ goto fail; ++ } ++ ++ str = "pkt_filter_enable"; ++ str_len = strlen(str); ++ bcm_strncpy_s(buf, sizeof(buf), str, str_len); ++ buf[str_len] = '\0'; ++ buf_len = str_len + 1; ++ ++ pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1); ++ ++ /* Parse packet filter id. */ ++ enable_parm.id = htod32(strtoul(argv[i], NULL, 0)); ++ ++ /* Parse enable/disable value. */ ++ enable_parm.enable = htod32(enable); ++ ++ buf_len += sizeof(enable_parm); ++ memcpy((char *)pkt_filterp, ++ &enable_parm, ++ sizeof(enable_parm)); ++ ++ /* Enable/disable the specified filter. */ ++ rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); ++ rc = rc >= 0 ? 0 : rc; ++ if (rc) ++ AP6211_DEBUG("%s: failed to add pktfilter %s, retcode = %d\n", ++ __FUNCTION__, arg, rc); ++ else ++ AP6211_DEBUG("%s: successfully added pktfilter %s\n", ++ __FUNCTION__, arg); ++ ++ /* Contorl the master mode */ ++ bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf)); ++ rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); ++ rc = rc >= 0 ? 0 : rc; ++ if (rc) ++ AP6211_DEBUG("%s: failed to add pktfilter %s, retcode = %d\n", ++ __FUNCTION__, arg, rc); ++ ++fail: ++ if (arg_org) ++ MFREE(dhd->osh, arg_org, strlen(arg) + 1); ++} ++ ++void ++dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) ++{ ++ const char *str; ++ wl_pkt_filter_t pkt_filter; ++ wl_pkt_filter_t *pkt_filterp; ++ int buf_len; ++ int str_len; ++ int rc; ++ uint32 mask_size; ++ uint32 pattern_size; ++ char *argv[8], * buf = 0; ++ int i = 0; ++ char *arg_save = 0, *arg_org = 0; ++#define BUF_SIZE 2048 ++ ++ if (!arg) ++ return; ++ ++ if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { ++ AP6211_ERR("%s: kmalloc failed\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ arg_org = arg_save; ++ ++ if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) { ++ AP6211_ERR("%s: kmalloc failed\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ memcpy(arg_save, arg, strlen(arg) + 1); ++ ++ if (strlen(arg) > BUF_SIZE) { ++ AP6211_ERR("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf)); ++ goto fail; ++ } ++ ++ argv[i] = bcmstrtok(&arg_save, " ", 0); ++ while (argv[i++]) ++ argv[i] = bcmstrtok(&arg_save, " ", 0); ++ ++ i = 0; ++ if (argv[i] == NULL) { ++ AP6211_ERR("No args provided\n"); ++ goto fail; ++ } ++ ++ str = "pkt_filter_add"; ++ str_len = strlen(str); ++ bcm_strncpy_s(buf, BUF_SIZE, str, str_len); ++ buf[ str_len ] = '\0'; ++ buf_len = str_len + 1; ++ ++ pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); ++ ++ /* Parse packet filter id. */ ++ pkt_filter.id = htod32(strtoul(argv[i], NULL, 0)); ++ ++ if (argv[++i] == NULL) { ++ AP6211_ERR("Polarity not provided\n"); ++ goto fail; ++ } ++ ++ /* Parse filter polarity. */ ++ pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0)); ++ ++ if (argv[++i] == NULL) { ++ AP6211_ERR("Filter type not provided\n"); ++ goto fail; ++ } ++ ++ /* Parse filter type. */ ++ pkt_filter.type = htod32(strtoul(argv[i], NULL, 0)); ++ ++ if (argv[++i] == NULL) { ++ AP6211_ERR("Offset not provided\n"); ++ goto fail; ++ } ++ ++ /* Parse pattern filter offset. */ ++ pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0)); ++ ++ if (argv[++i] == NULL) { ++ AP6211_ERR("Bitmask not provided\n"); ++ goto fail; ++ } ++ ++ /* Parse pattern filter mask. */ ++ mask_size = ++ htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern)); ++ ++ if (argv[++i] == NULL) { ++ AP6211_ERR("Pattern not provided\n"); ++ goto fail; ++ } ++ ++ /* Parse pattern filter pattern. */ ++ pattern_size = ++ htod32(wl_pattern_atoh(argv[i], ++ (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); ++ ++ if (mask_size != pattern_size) { ++ AP6211_ERR("Mask and pattern not the same size\n"); ++ goto fail; ++ } ++ ++ pkt_filter.u.pattern.size_bytes = mask_size; ++ buf_len += WL_PKT_FILTER_FIXED_LEN; ++ buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); ++ ++ /* Keep-alive attributes are set in local variable (keep_alive_pkt), and ++ ** then memcpy'ed into buffer (keep_alive_pktp) since there is no ++ ** guarantee that the buffer is properly aligned. ++ */ ++ memcpy((char *)pkt_filterp, ++ &pkt_filter, ++ WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); ++ ++ rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); ++ rc = rc >= 0 ? 0 : rc; ++ ++ if (rc) ++ AP6211_DEBUG("%s: failed to add pktfilter %s, retcode = %d\n", ++ __FUNCTION__, arg, rc); ++ else ++ AP6211_DEBUG("%s: successfully added pktfilter %s\n", ++ __FUNCTION__, arg); ++ ++fail: ++ if (arg_org) ++ MFREE(dhd->osh, arg_org, strlen(arg) + 1); ++ ++ if (buf) ++ MFREE(dhd->osh, buf, BUF_SIZE); ++} ++#endif /* PKT_FILTER_SUPPORT */ ++ ++/* ========================== */ ++/* ==== ARP OFFLOAD SUPPORT = */ ++/* ========================== */ ++#ifdef ARP_OFFLOAD_SUPPORT ++void ++dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode) ++{ ++ char iovbuf[32]; ++ int retcode; ++ ++ bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf)); ++ retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ retcode = retcode >= 0 ? 0 : retcode; ++ if (retcode) ++ AP6211_DEBUG("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n", ++ __FUNCTION__, arp_mode, retcode); ++ else ++ AP6211_DEBUG("%s: successfully set ARP offload mode to 0x%x\n", ++ __FUNCTION__, arp_mode); ++} ++ ++void ++dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) ++{ ++ char iovbuf[32]; ++ int retcode; ++ ++ bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf)); ++ retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ retcode = retcode >= 0 ? 0 : retcode; ++ if (retcode) ++ AP6211_DEBUG("%s: failed to enabe ARP offload to %d, retcode = %d\n", ++ __FUNCTION__, arp_enable, retcode); ++ else ++ AP6211_DEBUG("%s: successfully enabed ARP offload to %d\n", ++ __FUNCTION__, arp_enable); ++ if (arp_enable) { ++ uint32 version; ++ bcm_mkiovar("arp_version", 0, 0, iovbuf, sizeof(iovbuf)); ++ retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); ++ if (retcode) { ++ AP6211_DEBUG("%s: fail to get version (maybe version 1:retcode = %d\n", ++ __FUNCTION__, retcode); ++ dhd->arp_version = 1; ++ } ++ else { ++ memcpy(&version, iovbuf, sizeof(version)); ++ AP6211_DEBUG("%s: ARP Version= %x\n", __FUNCTION__, version); ++ dhd->arp_version = version; ++ } ++ } ++} ++ ++void ++dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx) ++{ ++ int ret = 0; ++ int iov_len = 0; ++ char iovbuf[128]; ++ ++ if (dhd == NULL) return; ++ if (dhd->arp_version == 1) ++ idx = 0; ++ ++ iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx) < 0)) ++ AP6211_ERR("%s failed code %d\n", __FUNCTION__, ret); ++} ++ ++void ++dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx) ++{ ++ int ret = 0; ++ int iov_len = 0; ++ char iovbuf[128]; ++ ++ if (dhd == NULL) return; ++ if (dhd->arp_version == 1) ++ idx = 0; ++ ++ iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 0) ++ AP6211_ERR("%s failed code %d\n", __FUNCTION__, ret); ++} ++ ++void ++dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx) ++{ ++ int iov_len = 0; ++ char iovbuf[32]; ++ int retcode; ++ ++ ++ if (dhd == NULL) return; ++ if (dhd->arp_version == 1) ++ idx = 0; ++ iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr, ++ sizeof(ipaddr), iovbuf, sizeof(iovbuf)); ++ retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); ++ ++ if (retcode) ++ AP6211_DEBUG("%s: ARP ip addr add failed, retcode = %d\n", ++ __FUNCTION__, retcode); ++ else ++ AP6211_DEBUG("%s: sARP H ipaddr entry added \n", ++ __FUNCTION__); ++} ++ ++int ++dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx) ++{ ++ int retcode, i; ++ int iov_len; ++ uint32 *ptr32 = buf; ++ bool clr_bottom = FALSE; ++ ++ if (!buf) ++ return -1; ++ if (dhd == NULL) return -1; ++ if (dhd->arp_version == 1) ++ idx = 0; ++ ++ iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen); ++ BCM_REFERENCE(iov_len); ++ retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, idx); ++ ++ if (retcode) { ++ AP6211_DEBUG("%s: ioctl WLC_GET_VAR error %d\n", ++ __FUNCTION__, retcode); ++ ++ return -1; ++ } ++ ++ /* clean up the buf, ascii reminder */ ++ for (i = 0; i < MAX_IPV4_ENTRIES; i++) { ++ if (!clr_bottom) { ++ if (*ptr32 == 0) ++ clr_bottom = TRUE; ++ } else { ++ *ptr32 = 0; ++ } ++ ptr32++; ++ } ++ ++ return 0; ++} ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++/* send up locally generated event */ ++void ++dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) ++{ ++ switch (ntoh32(event->event_type)) { ++#ifdef WLBTAMP ++ case WLC_E_BTA_HCI_EVENT: ++ break; ++#endif /* WLBTAMP */ ++ default: ++ break; ++ } ++ ++ /* Call per-port handler. */ ++ dhd_sendup_event(dhdp, event, data); ++} ++ ++ ++/* ++ * returns = TRUE if associated, FALSE if not associated ++ */ ++bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval) ++{ ++ char bssid[6], zbuf[6]; ++ int ret = -1; ++ ++ bzero(bssid, 6); ++ bzero(zbuf, 6); ++ ++ ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0); ++ AP6211_DEBUG(" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret); ++ ++ if (ret == BCME_NOTASSOCIATED) { ++ AP6211_DEBUG("%s: not associated! res:%d\n", __FUNCTION__, ret); ++ } ++ ++ if (retval) ++ *retval = ret; ++ ++ if (ret < 0) ++ return FALSE; ++ ++ if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) { ++ /* STA is assocoated BSSID is non zero */ ++ ++ if (bss_buf) { ++ /* return bss if caller provided buf */ ++ memcpy(bss_buf, bssid, ETHER_ADDR_LEN); ++ } ++ return TRUE; ++ } else { ++ AP6211_DEBUG("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__); ++ return FALSE; ++ } ++} ++ ++ ++/* Function to estimate possible DTIM_SKIP value */ ++int ++dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd) ++{ ++ int bcn_li_dtim; ++ int ret = -1; ++ int dtim_assoc = 0; ++ ++ bcn_li_dtim = dhd->suspend_bcn_li_dtim; ++ ++ /* Check if associated */ ++ if (dhd_is_associated(dhd, NULL, NULL) == FALSE) { ++ AP6211_DEBUG("%s NOT assoc ret %d\n", __FUNCTION__, ret); ++ goto exit; ++ } ++ ++ /* if assoc grab ap's dtim value */ ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, ++ &dtim_assoc, sizeof(dtim_assoc), FALSE, 0)) < 0) { ++ AP6211_ERR("%s failed code %d\n", __FUNCTION__, ret); ++ goto exit; ++ } ++ ++ AP6211_ERR("%s bcn_li_dtim=%d DTIM=%d Listen=%d\n", ++ __FUNCTION__, bcn_li_dtim, dtim_assoc, LISTEN_INTERVAL); ++ ++ /* if not assocated just eixt */ ++ if (dtim_assoc == 0) { ++ goto exit; ++ } ++ ++ /* check if sta listen interval fits into AP dtim */ ++ if (dtim_assoc > LISTEN_INTERVAL) { ++ /* AP DTIM to big for our Listen Interval : no dtim skiping */ ++ bcn_li_dtim = 1; ++ AP6211_ERR("%s DTIM=%d > Listen=%d : too big ...\n", ++ __FUNCTION__, dtim_assoc, LISTEN_INTERVAL); ++ goto exit; ++ } ++ ++ if ((bcn_li_dtim * dtim_assoc) > LISTEN_INTERVAL) { ++ /* Round up dtim_skip to fit into STAs Listen Interval */ ++ bcn_li_dtim = (int)(LISTEN_INTERVAL / dtim_assoc); ++ AP6211_DEBUG("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim); ++ } ++ ++exit: ++ return bcn_li_dtim; ++} ++ ++/* Check if the mode supports STA MODE */ ++bool dhd_support_sta_mode(dhd_pub_t *dhd) ++{ ++ ++#ifdef WL_CFG80211 ++ if (!(dhd->op_mode & DHD_FLAG_STA_MODE)) ++ return FALSE; ++ else ++#endif /* WL_CFG80211 */ ++ return TRUE; ++} ++ ++#if defined(PNO_SUPPORT) ++int ++dhd_pno_clean(dhd_pub_t *dhd) ++{ ++ char iovbuf[128]; ++ int pfn_enabled = 0; ++ int iov_len = 0; ++ int ret; ++ ++ /* Disable pfn */ ++ iov_len = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) >= 0) { ++ /* clear pfn */ ++ iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf)); ++ if (iov_len) { ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, ++ iov_len, TRUE, 0)) < 0) { ++ AP6211_ERR("%s failed code %d\n", __FUNCTION__, ret); ++ } ++ } ++ else { ++ ret = -1; ++ AP6211_ERR("%s failed code %d\n", __FUNCTION__, iov_len); ++ } ++ } ++ else ++ AP6211_ERR("%s failed code %d\n", __FUNCTION__, ret); ++ ++ return ret; ++} ++ ++int ++dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) ++{ ++ char iovbuf[128]; ++ int ret = -1; ++ ++ if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) { ++ AP6211_ERR("%s error exit\n", __FUNCTION__); ++ return ret; ++ } ++ ++#ifndef WL_SCHED_SCAN ++ if (!dhd_support_sta_mode(dhd)) ++ return (ret); ++ ++ memset(iovbuf, 0, sizeof(iovbuf)); ++ ++ if ((pfn_enabled) && (dhd_is_associated(dhd, NULL, NULL) == TRUE)) { ++ AP6211_ERR("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__); ++ return ret; ++ } ++#endif /* !WL_SCHED_SCAN */ ++ ++ /* Enable/disable PNO */ ++ if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) { ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, ++ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { ++ AP6211_ERR("%s failed for error=%d\n", __FUNCTION__, ret); ++ return ret; ++ } ++ else { ++ dhd->pno_enable = pfn_enabled; ++ AP6211_DEBUG("%s set pno as %s\n", ++ __FUNCTION__, dhd->pno_enable ? "Enable" : "Disable"); ++ } ++ } ++ else AP6211_ERR("%s failed err=%d\n", __FUNCTION__, ret); ++ ++ return ret; ++} ++ ++/* Function to execute combined scan */ ++int ++dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr, ++ int pno_repeat, int pno_freq_expo_max) ++{ ++ int err = -1; ++ char iovbuf[128]; ++ int k, i; ++ wl_pfn_param_t pfn_param; ++ wl_pfn_t pfn_element; ++ uint len = 0; ++ ++ AP6211_DEBUG("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, scan_fr); ++ ++ if ((!dhd) || (!ssids_local)) { ++ AP6211_ERR("%s error exit(%s %s)\n", __FUNCTION__, ++ (!dhd)?"dhd is null":"", (!ssids_local)?"ssid is null":""); ++ err = -1; ++ return err; ++ } ++#ifndef WL_SCHED_SCAN ++ if (!dhd_support_sta_mode(dhd)) ++ return err; ++#endif /* !WL_SCHED_SCAN */ ++ ++ /* Check for broadcast ssid */ ++ for (k = 0; k < nssid; k++) { ++ if (!ssids_local[k].SSID_len) { ++ AP6211_ERR("%d: Broadcast SSID is ilegal for PNO setting\n", k); ++ return err; ++ } ++ } ++/* #define PNO_DUMP 1 */ ++#ifdef PNO_DUMP ++ { ++ int j; ++ for (j = 0; j < nssid; j++) { ++ AP6211_ERR("%d: scan for %s size =%d\n", j, ++ ssids_local[j].SSID, ssids_local[j].SSID_len); ++ } ++ } ++#endif /* PNO_DUMP */ ++ ++ /* clean up everything */ ++ if ((err = dhd_pno_clean(dhd)) < 0) { ++ AP6211_ERR("%s failed error=%d\n", __FUNCTION__, err); ++ return err; ++ } ++ memset(iovbuf, 0, sizeof(iovbuf)); ++ memset(&pfn_param, 0, sizeof(pfn_param)); ++ memset(&pfn_element, 0, sizeof(pfn_element)); ++ ++ /* set pfn parameters */ ++ pfn_param.version = htod32(PFN_VERSION); ++ pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT)); ++ ++ /* check and set extra pno params */ ++ if ((pno_repeat != 0) || (pno_freq_expo_max != 0)) { ++ pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); ++ pfn_param.repeat = (uchar) (pno_repeat); ++ pfn_param.exp = (uchar) (pno_freq_expo_max); ++ } ++ /* set up pno scan fr */ ++ if (scan_fr != 0) ++ pfn_param.scan_freq = htod32(scan_fr); ++ ++ if (pfn_param.scan_freq > PNO_SCAN_MAX_FW_SEC) { ++ AP6211_ERR("%s pno freq above %d sec\n", __FUNCTION__, PNO_SCAN_MAX_FW_SEC); ++ return err; ++ } ++ if (pfn_param.scan_freq < PNO_SCAN_MIN_FW_SEC) { ++ AP6211_ERR("%s pno freq less %d sec\n", __FUNCTION__, PNO_SCAN_MIN_FW_SEC); ++ return err; ++ } ++ ++ len = bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf)); ++ if ((err = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) { ++ AP6211_ERR("%s pfn_set failed for error=%d\n", ++ __FUNCTION__, err); ++ return err; ++ } ++ ++ /* set all pfn ssid */ ++ for (i = 0; i < nssid; i++) { ++ ++ pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); ++ pfn_element.auth = (DOT11_OPEN_SYSTEM); ++ pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); ++ pfn_element.wsec = htod32(0); ++ pfn_element.infra = htod32(1); ++ pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT); ++ memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID, ssids_local[i].SSID_len); ++ pfn_element.ssid.SSID_len = ssids_local[i].SSID_len; ++ ++ if ((len = ++ bcm_mkiovar("pfn_add", (char *)&pfn_element, ++ sizeof(pfn_element), iovbuf, sizeof(iovbuf))) > 0) { ++ if ((err = ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) { ++ AP6211_ERR("%s failed for i=%d error=%d\n", ++ __FUNCTION__, i, err); ++ return err; ++ } ++ else ++ AP6211_DEBUG("%s set OK with PNO time=%d repeat=%d max_adjust=%d\n", ++ __FUNCTION__, pfn_param.scan_freq, ++ pfn_param.repeat, pfn_param.exp); ++ } ++ else AP6211_ERR("%s failed err=%d\n", __FUNCTION__, err); ++ } ++ ++ /* Enable PNO */ ++ /* dhd_pno_enable(dhd, 1); */ ++ return err; ++} ++ ++int ++dhd_pno_get_status(dhd_pub_t *dhd) ++{ ++ int ret = -1; ++ ++ if (!dhd) ++ return ret; ++ else ++ return (dhd->pno_enable); ++} ++ ++#endif /* OEM_ANDROID && PNO_SUPPORT */ ++ ++#if defined(KEEP_ALIVE) ++int dhd_keep_alive_onoff(dhd_pub_t *dhd) ++{ ++ char buf[256]; ++ const char *str; ++ wl_mkeep_alive_pkt_t mkeep_alive_pkt; ++ wl_mkeep_alive_pkt_t *mkeep_alive_pktp; ++ int buf_len; ++ int str_len; ++ int res = -1; ++ ++ if (!dhd_support_sta_mode(dhd)) ++ return res; ++ ++ AP6211_DEBUG("%s execution\n", __FUNCTION__); ++ ++ str = "mkeep_alive"; ++ str_len = strlen(str); ++ strncpy(buf, str, str_len); ++ buf[ str_len ] = '\0'; ++ mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1); ++ mkeep_alive_pkt.period_msec = CUSTOM_KEEP_ALIVE_SETTING; ++ buf_len = str_len + 1; ++ mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); ++ mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); ++ /* Setup keep alive zero for null packet generation */ ++ mkeep_alive_pkt.keep_alive_id = 0; ++ mkeep_alive_pkt.len_bytes = 0; ++ buf_len += WL_MKEEP_ALIVE_FIXED_LEN; ++ bzero(mkeep_alive_pkt.data, sizeof(mkeep_alive_pkt.data)); ++ /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and ++ * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no ++ * guarantee that the buffer is properly aligned. ++ */ ++ memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); ++ ++ res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); ++ ++ return res; ++} ++#endif /* defined(KEEP_ALIVE) */ ++/* Android ComboSCAN support */ ++ ++/* ++ * data parsing from ComboScan tlv list ++*/ ++int ++wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, ++ int input_size, int *bytes_left) ++{ ++ char* str; ++ uint16 short_temp; ++ uint32 int_temp; ++ ++ if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { ++ AP6211_ERR("%s error paramters\n", __FUNCTION__); ++ return -1; ++ } ++ str = *list_str; ++ ++ /* Clean all dest bytes */ ++ memset(dst, 0, dst_size); ++ while (*bytes_left > 0) { ++ ++ if (str[0] != token) { ++ AP6211_DEBUG("%s NOT Type=%d get=%d left_parse=%d \n", ++ __FUNCTION__, token, str[0], *bytes_left); ++ return -1; ++ } ++ ++ *bytes_left -= 1; ++ str += 1; ++ ++ if (input_size == 1) { ++ memcpy(dst, str, input_size); ++ } ++ else if (input_size == 2) { ++ memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)), ++ input_size); ++ } ++ else if (input_size == 4) { ++ memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)), ++ input_size); ++ } ++ ++ *bytes_left -= input_size; ++ str += input_size; ++ *list_str = str; ++ return 1; ++ } ++ return 1; ++} ++ ++/* ++ * channel list parsing from cscan tlv list ++*/ ++int ++wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, ++ int channel_num, int *bytes_left) ++{ ++ char* str; ++ int idx = 0; ++ ++ if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { ++ AP6211_ERR("%s error paramters\n", __FUNCTION__); ++ return -1; ++ } ++ str = *list_str; ++ ++ while (*bytes_left > 0) { ++ ++ if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) { ++ *list_str = str; ++ AP6211_DEBUG("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0]); ++ return idx; ++ } ++ /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */ ++ *bytes_left -= 1; ++ str += 1; ++ ++ if (str[0] == 0) { ++ /* All channels */ ++ channel_list[idx] = 0x0; ++ } ++ else { ++ channel_list[idx] = (uint16)str[0]; ++ AP6211_DEBUG("%s channel=%d \n", __FUNCTION__, channel_list[idx]); ++ } ++ *bytes_left -= 1; ++ str += 1; ++ ++ if (idx++ > 255) { ++ AP6211_ERR("%s Too many channels \n", __FUNCTION__); ++ return -1; ++ } ++ } ++ ++ *list_str = str; ++ return idx; ++} ++ ++/* ++ * SSIDs list parsing from cscan tlv list ++ */ ++int ++wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left) ++{ ++ char* str; ++ int idx = 0; ++ ++ if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { ++ AP6211_ERR("%s error paramters\n", __FUNCTION__); ++ return -1; ++ } ++ str = *list_str; ++ while (*bytes_left > 0) { ++ ++ if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { ++ *list_str = str; ++ AP6211_DEBUG("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0]); ++ return idx; ++ } ++ ++ /* Get proper CSCAN_TLV_TYPE_SSID_IE */ ++ *bytes_left -= 1; ++ str += 1; ++ ++ if (str[0] == 0) { ++ /* Broadcast SSID */ ++ ssid[idx].SSID_len = 0; ++ memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); ++ *bytes_left -= 1; ++ str += 1; ++ ++ AP6211_DEBUG("BROADCAST SCAN left=%d\n", *bytes_left); ++ } ++ else if (str[0] <= DOT11_MAX_SSID_LEN) { ++ /* Get proper SSID size */ ++ ssid[idx].SSID_len = str[0]; ++ *bytes_left -= 1; ++ str += 1; ++ ++ /* Get SSID */ ++ if (ssid[idx].SSID_len > *bytes_left) { ++ AP6211_ERR("%s out of memory range len=%d but left=%d\n", ++ __FUNCTION__, ssid[idx].SSID_len, *bytes_left); ++ return -1; ++ } ++ ++ memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); ++ ++ *bytes_left -= ssid[idx].SSID_len; ++ str += ssid[idx].SSID_len; ++ ++ AP6211_DEBUG("%s :size=%d left=%d\n", ++ (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left); ++ } ++ else { ++ AP6211_ERR("### SSID size more that %d\n", str[0]); ++ return -1; ++ } ++ ++ if (idx++ > max) { ++ AP6211_ERR("%s number of SSIDs more that %d\n", __FUNCTION__, idx); ++ return -1; ++ } ++ } ++ ++ *list_str = str; ++ return idx; ++} ++ ++/* Parse a comma-separated list from list_str into ssid array, starting ++ * at index idx. Max specifies size of the ssid array. Parses ssids ++ * and returns updated idx; if idx >= max not all fit, the excess have ++ * not been copied. Returns -1 on empty string, or on ssid too long. ++ */ ++int ++wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max) ++{ ++ char* str, *ptr; ++ ++ if ((list_str == NULL) || (*list_str == NULL)) ++ return -1; ++ ++ for (str = *list_str; str != NULL; str = ptr) { ++ ++ /* check for next TAG */ ++ if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) { ++ *list_str = str + strlen(GET_CHANNEL); ++ return idx; ++ } ++ ++ if ((ptr = strchr(str, ',')) != NULL) { ++ *ptr++ = '\0'; ++ } ++ ++ if (strlen(str) > DOT11_MAX_SSID_LEN) { ++ AP6211_ERR("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN); ++ return -1; ++ } ++ ++ if (strlen(str) == 0) ++ ssid[idx].SSID_len = 0; ++ ++ if (idx < max) { ++ bzero(ssid[idx].SSID, sizeof(ssid[idx].SSID)); ++ strncpy((char*)ssid[idx].SSID, str, sizeof(ssid[idx].SSID) - 1); ++ ssid[idx].SSID_len = strlen(str); ++ } ++ idx++; ++ } ++ return idx; ++} ++ ++/* ++ * Parse channel list from iwpriv CSCAN ++ */ ++int ++wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num) ++{ ++ int num; ++ int val; ++ char* str; ++ char* endptr = NULL; ++ ++ if ((list_str == NULL)||(*list_str == NULL)) ++ return -1; ++ ++ str = *list_str; ++ num = 0; ++ while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) { ++ val = (int)strtoul(str, &endptr, 0); ++ if (endptr == str) { ++ AP6211_ERR("could not parse channel number starting at" ++ " substring \"%s\" in list:\n%s\n", ++ str, *list_str); ++ return -1; ++ } ++ str = endptr + strspn(endptr, " ,"); ++ ++ if (num == channel_num) { ++ AP6211_ERR("too many channels (more than %d) in channel list:\n%s\n", ++ channel_num, *list_str); ++ return -1; ++ } ++ ++ channel_list[num++] = (uint16)val; ++ } ++ *list_str = str; ++ return num; ++} +diff --git a/drivers/net/wireless/ap6211/dhd_custom_gpio.c b/drivers/net/wireless/ap6211/dhd_custom_gpio.c +new file mode 100755 +index 0000000..afdb9b3 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_custom_gpio.c +@@ -0,0 +1,313 @@ ++/* ++* Customer code to add GPIO control during WLAN start/stop ++* Copyright (C) 1999-2012, Broadcom Corporation ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2 (the "GPL"), ++* available at http://www.broadcom.com/licenses/GPLv2.php, with the ++* following added to such license: ++* ++* As a special exception, the copyright holders of this software give you ++* permission to link this software with independent modules, and to copy and ++* distribute the resulting executable under terms of your choice, provided that ++* you also meet, for each linked independent module, the terms and conditions of ++* the license of that module. An independent module is a module which is not ++* derived from this software. The special exception does not apply to any ++* modifications of the software. ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a license ++* other than the GPL, without Broadcom's express prior written consent. ++* ++* $Id: dhd_custom_gpio.c 353167 2012-08-24 22:11:30Z $ ++*/ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++extern void sunximmc_rescan_card(unsigned id, unsigned insert); ++ ++#ifdef CUSTOMER_HW ++#include ++#if defined(CUSTOMER_OOB) ++extern int bcm_wlan_get_oob_irq(void); ++#endif ++extern void bcm_wlan_power_off(int); ++extern void bcm_wlan_power_on(int); ++#endif /* CUSTOMER_HW */ ++#if defined(CUSTOMER_HW2) ++#ifdef CONFIG_WIFI_CONTROL_FUNC ++int wifi_set_power(int on, unsigned long msec); ++int wifi_get_irq_number(unsigned long *irq_flags_ptr); ++int wifi_get_mac_addr(unsigned char *buf); ++void *wifi_get_country_code(char *ccode); ++#else ++int wifi_set_power(int on, unsigned long msec) { return -1; } ++int wifi_get_irq_number(unsigned long *irq_flags_ptr) { return -1; } ++int wifi_get_mac_addr(unsigned char *buf) { return -1; } ++void *wifi_get_country_code(char *ccode) { return NULL; } ++#endif /* CONFIG_WIFI_CONTROL_FUNC */ ++#endif ++ ++#if defined(OOB_INTR_ONLY) ++ ++#if defined(BCMLXSDMMC) ++extern int sdioh_mmc_irq(int irq); ++#endif /* (BCMLXSDMMC) */ ++ ++#ifdef CUSTOMER_HW3 ++#include ++#endif ++ ++/* Customer specific Host GPIO defintion */ ++static int dhd_oob_gpio_num = 2; ++ ++module_param(dhd_oob_gpio_num, int, 0644); ++MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number"); ++ ++/* This function will return: ++ * 1) return : Host gpio interrupt number per customer platform ++ * 2) irq_flags_ptr : Type of Host interrupt as Level or Edge ++ * ++ * NOTE : ++ * Customer should check his platform definitions ++ * and his Host Interrupt spec ++ * to figure out the proper setting for his platform. ++ * Broadcom provides just reference settings as example. ++ * ++ */ ++int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr) ++{ ++ int host_oob_irq = -1; ++ ++#if defined(CUSTOMER_HW2) ++ host_oob_irq = wifi_get_irq_number(irq_flags_ptr); ++ ++#elif defined(CUSTOMER_OOB) ++ host_oob_irq = bcm_wlan_get_oob_irq(); ++ AP6211_DEBUG("irq=%d, flags=0x%08lx\n", host_oob_irq, *irq_flags_ptr); ++#else ++#if defined(CUSTOM_OOB_GPIO_NUM) ++ if (dhd_oob_gpio_num < 0) { ++ dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; ++ } ++#endif /* CUSTOMER_OOB_GPIO_NUM */ ++ ++ if (dhd_oob_gpio_num < 0) { ++ AP6211_ERR("%s: ERROR customer specific Host GPIO is NOT defined \n", ++ __FUNCTION__); ++ return (dhd_oob_gpio_num); ++ } ++ ++ AP6211_ERR("%s: customer specific Host GPIO number is (%d)\n", ++ __FUNCTION__, dhd_oob_gpio_num); ++ ++#if defined CUSTOMER_HW ++ AP6211_ERR("%s: should not be here!\n", __FUNCTION__); ++#elif defined CUSTOMER_HW3 ++ gpio_request(dhd_oob_gpio_num, "oob irq"); ++ host_oob_irq = gpio_to_irq(dhd_oob_gpio_num); ++ gpio_direction_input(dhd_oob_gpio_num); ++#endif /* CUSTOMER_HW */ ++#endif ++ ++ return (host_oob_irq); ++} ++#endif ++ ++/* Customer function to control hw specific wlan gpios */ ++void ++dhd_customer_gpio_wlan_ctrl(int onoff) ++{ ++ static int sdc_id = 3; ++ ++ switch (onoff) { ++ case WLAN_RESET_OFF: ++ AP6211_DEBUG("%s: call customer specific GPIO to insert WLAN RESET\n", ++ __FUNCTION__); ++#ifdef CUSTOMER_HW ++ ap6211_gpio_wifi_power(0); ++#endif /* CUSTOMER_HW */ ++#if defined(CUSTOMER_HW2) ++ wifi_set_power(0, 0); ++#endif ++ mdelay(100); ++ AP6211_ERR("WLAN placed in RESET\n"); ++ break; ++ ++ case WLAN_RESET_ON: ++ AP6211_DEBUG("%s: callc customer specific GPIO to remove WLAN RESET\n", ++ __FUNCTION__); ++#ifdef CUSTOMER_HW ++ ap6211_gpio_wifi_power(1); ++#endif /* CUSTOMER_HW */ ++#if defined(CUSTOMER_HW2) ++ wifi_set_power(1, 0); ++#endif ++ mdelay(100); ++ AP6211_ERR("WLAN going back to live\n"); ++ break; ++ ++ case WLAN_POWER_OFF: ++ AP6211_DEBUG("%s: call customer specific GPIO to turn off WL_REG_ON\n", ++ __FUNCTION__); ++#ifdef CUSTOMER_HW ++ ap6211_gpio_wifi_power(0); ++ sunximmc_rescan_card(sdc_id, 0); ++#endif /* CUSTOMER_HW */ ++ AP6211_ERR("WLAN placed in POWER OFF\n"); ++ break; ++ ++ case WLAN_POWER_ON: ++ AP6211_DEBUG("%s: call customer specific GPIO to turn on WL_REG_ON\n", ++ __FUNCTION__); ++#ifdef CUSTOMER_HW ++ ap6211_gpio_wifi_power(1); ++ sunximmc_rescan_card(sdc_id, 1); ++ /* Lets customer power to get stable */ ++#endif /* CUSTOMER_HW */ ++ mdelay(100); ++ AP6211_ERR("WLAN placed in POWER ON\n"); ++ break; ++ } ++} ++ ++#ifdef GET_CUSTOM_MAC_ENABLE ++/* Function to get custom MAC address */ ++int ++dhd_custom_get_mac_address(unsigned char *buf) ++{ ++ int ret = 0; ++ ++ AP6211_DEBUG("%s Enter\n", __FUNCTION__); ++ if (!buf) ++ return -EINVAL; ++ ++ /* Customer access to MAC address stored outside of DHD driver */ ++#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) ++ ret = wifi_get_mac_addr(buf); ++#endif ++ ++#ifdef EXAMPLE_GET_MAC ++ /* EXAMPLE code */ ++ { ++ struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}}; ++ bcopy((char *)&ea_example, buf, sizeof(struct ether_addr)); ++ } ++#endif /* EXAMPLE_GET_MAC */ ++ ++ return ret; ++} ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++ ++/* Customized Locale table : OPTIONAL feature */ ++const struct cntry_locales_custom translate_custom_table[] = { ++/* Table should be filled out based on custom platform regulatory requirement */ ++#ifdef EXAMPLE_TABLE ++ {"", "XY", 4}, /* Universal if Country code is unknown or empty */ ++ {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */ ++ {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */ ++ {"EU", "EU", 5}, /* European union countries to : EU regrev 05 */ ++ {"AT", "EU", 5}, ++ {"BE", "EU", 5}, ++ {"BG", "EU", 5}, ++ {"CY", "EU", 5}, ++ {"CZ", "EU", 5}, ++ {"DK", "EU", 5}, ++ {"EE", "EU", 5}, ++ {"FI", "EU", 5}, ++ {"FR", "EU", 5}, ++ {"DE", "EU", 5}, ++ {"GR", "EU", 5}, ++ {"HU", "EU", 5}, ++ {"IE", "EU", 5}, ++ {"IT", "EU", 5}, ++ {"LV", "EU", 5}, ++ {"LI", "EU", 5}, ++ {"LT", "EU", 5}, ++ {"LU", "EU", 5}, ++ {"MT", "EU", 5}, ++ {"NL", "EU", 5}, ++ {"PL", "EU", 5}, ++ {"PT", "EU", 5}, ++ {"RO", "EU", 5}, ++ {"SK", "EU", 5}, ++ {"SI", "EU", 5}, ++ {"ES", "EU", 5}, ++ {"SE", "EU", 5}, ++ {"GB", "EU", 5}, ++ {"KR", "XY", 3}, ++ {"AU", "XY", 3}, ++ {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */ ++ {"TW", "XY", 3}, ++ {"AR", "XY", 3}, ++ {"MX", "XY", 3}, ++ {"IL", "IL", 0}, ++ {"CH", "CH", 0}, ++ {"TR", "TR", 0}, ++ {"NO", "NO", 0}, ++#endif /* EXMAPLE_TABLE */ ++}; ++ ++ ++/* Customized Locale convertor ++* input : ISO 3166-1 country abbreviation ++* output: customized cspec ++*/ ++void get_customized_country_code(char *country_iso_code, wl_country_t *cspec) ++{ ++#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++ ++ struct cntry_locales_custom *cloc_ptr; ++ ++ if (!cspec) ++ return; ++ ++ cloc_ptr = wifi_get_country_code(country_iso_code); ++ if (cloc_ptr) { ++ strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ); ++ cspec->rev = cloc_ptr->custom_locale_rev; ++ } ++ return; ++#else ++ int size, i; ++ ++ size = ARRAYSIZE(translate_custom_table); ++ ++ if (cspec == 0) ++ return; ++ ++ if (size == 0) ++ return; ++ ++ for (i = 0; i < size; i++) { ++ if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) { ++ memcpy(cspec->ccode, ++ translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ); ++ cspec->rev = translate_custom_table[i].custom_locale_rev; ++ return; ++ } ++ } ++#ifdef EXAMPLE_TABLE ++ /* if no country code matched return first universal code from translate_custom_table */ ++ memcpy(cspec->ccode, translate_custom_table[0].custom_locale, WLC_CNTRY_BUF_SZ); ++ cspec->rev = translate_custom_table[0].custom_locale_rev; ++#endif /* EXMAPLE_TABLE */ ++ return; ++#endif /* defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) */ ++} +diff --git a/drivers/net/wireless/ap6211/dhd_dbg.h b/drivers/net/wireless/ap6211/dhd_dbg.h +new file mode 100755 +index 0000000..67cd2e5 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_dbg.h +@@ -0,0 +1,79 @@ ++/* ++ * Debug/trace/assert driver definitions for Dongle Host Driver. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_dbg.h 353490 2012-08-27 21:10:02Z $ ++ */ ++ ++#ifndef _dhd_dbg_ ++#define _dhd_dbg_ ++ ++#define USE_NET_RATELIMIT net_ratelimit() ++ ++#if defined(DHD_DEBUG) ++ ++#define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL) ++#define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL) ++#define DHD_INFO_ON() (dhd_msg_level & DHD_INFO_VAL) ++#define DHD_DATA_ON() (dhd_msg_level & DHD_DATA_VAL) ++#define DHD_CTL_ON() (dhd_msg_level & DHD_CTL_VAL) ++#define DHD_TIMER_ON() (dhd_msg_level & DHD_TIMER_VAL) ++#define DHD_HDRS_ON() (dhd_msg_level & DHD_HDRS_VAL) ++#define DHD_BYTES_ON() (dhd_msg_level & DHD_BYTES_VAL) ++#define DHD_INTR_ON() (dhd_msg_level & DHD_INTR_VAL) ++#define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL) ++#define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL) ++#define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL) ++#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL) ++#define DHD_ARPOE_ON() (dhd_msg_level & DHD_ARPOE_VAL) ++#define DHD_REORDER_ON() (dhd_msg_level & DHD_REORDER_VAL) ++ ++#else /* defined(BCMDBG) || defined(DHD_DEBUG) */ ++ ++#define DHD_ERROR_ON() 0 ++#define DHD_TRACE_ON() 0 ++#define DHD_INFO_ON() 0 ++#define DHD_DATA_ON() 0 ++#define DHD_CTL_ON() 0 ++#define DHD_TIMER_ON() 0 ++#define DHD_HDRS_ON() 0 ++#define DHD_BYTES_ON() 0 ++#define DHD_INTR_ON() 0 ++#define DHD_GLOM_ON() 0 ++#define DHD_EVENT_ON() 0 ++#define DHD_BTA_ON() 0 ++#define DHD_ISCAN_ON() 0 ++#define DHD_ARPOE_ON() 0 ++#define DHD_REORDER_ON() 0 ++#endif ++ ++#define DHD_LOG(args) ++ ++#define DHD_BLOG(cp, size) ++ ++#define DHD_NONE(args) ++extern int dhd_msg_level; ++ ++/* Defines msg bits */ ++#include ++ ++#endif /* _dhd_dbg_ */ +diff --git a/drivers/net/wireless/ap6211/dhd_gpio.c b/drivers/net/wireless/ap6211/dhd_gpio.c +new file mode 100755 +index 0000000..dae0dd3 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_gpio.c +@@ -0,0 +1,47 @@ ++/* ++* Customer code to add GPIO control during WLAN start/stop ++* Copyright (C) 1999-2011, Broadcom Corporation ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2 (the "GPL"), ++* available at http://www.broadcom.com/licenses/GPLv2.php, with the ++* following added to such license: ++* ++* As a special exception, the copyright holders of this software give you ++* permission to link this software with independent modules, and to copy and ++* distribute the resulting executable under terms of your choice, provided that ++* you also meet, for each linked independent module, the terms and conditions of ++* the license of that module. An independent module is a module which is not ++* derived from this software. The special exception does not apply to any ++* modifications of the software. ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a license ++* other than the GPL, without Broadcom's express prior written consent. ++* ++* $Id: dhd_custom_gpio.c,v 1.2.42.1 2010-10-19 00:41:09 Exp $ ++*/ ++ ++#include ++ ++#include ++#include ++ ++#ifdef CUSTOMER_HW ++ ++extern int __gpio_to_irq(unsigned gpio); ++extern int gpio_direction_input(unsigned gpio); ++extern int gpio_request(unsigned gpio, const char *label); ++extern void gpio_free(unsigned gpio); ++ ++#ifdef CUSTOMER_OOB ++extern int wl_host_wake_irqno; ++int bcm_wlan_get_oob_irq(void) ++{ ++ return wl_host_wake_irqno; ++} ++#endif ++ ++ ++#endif /* CUSTOMER_HW */ +diff --git a/drivers/net/wireless/ap6211/dhd_ip.c b/drivers/net/wireless/ap6211/dhd_ip.c +new file mode 100755 +index 0000000..05abc93 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_ip.c +@@ -0,0 +1,111 @@ ++/* ++ * IP Packet Parser Module. ++ * ++ * Copyright (C) 1999-2013, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id$ ++ */ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++/* special values */ ++/* 802.3 llc/snap header */ ++static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; ++ ++pkt_frag_t pkt_frag_info(osl_t *osh, void *p) ++{ ++ uint8 *frame; ++ int length; ++ uint8 *pt; /* Pointer to type field */ ++ uint16 ethertype; ++ struct ipv4_hdr *iph; /* IP frame pointer */ ++ int ipl; /* IP frame length */ ++ uint16 iph_frag; ++ ++ ASSERT(osh && p); ++ ++ frame = PKTDATA(osh, p); ++ length = PKTLEN(osh, p); ++ ++ /* Process Ethernet II or SNAP-encapsulated 802.3 frames */ ++ if (length < ETHER_HDR_LEN) { ++ AP6211_DEBUG("%s: short eth frame (%d)\n", __FUNCTION__, length); ++ return DHD_PKT_FRAG_NONE; ++ } else if (ntoh16(*(uint16 *)(frame + ETHER_TYPE_OFFSET)) >= ETHER_TYPE_MIN) { ++ /* Frame is Ethernet II */ ++ pt = frame + ETHER_TYPE_OFFSET; ++ } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN && ++ !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) { ++ pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN; ++ } else { ++ AP6211_DEBUG("%s: non-SNAP 802.3 frame\n", __FUNCTION__); ++ return DHD_PKT_FRAG_NONE; ++ } ++ ++ ethertype = ntoh16(*(uint16 *)pt); ++ ++ /* Skip VLAN tag, if any */ ++ if (ethertype == ETHER_TYPE_8021Q) { ++ pt += VLAN_TAG_LEN; ++ ++ if (pt + ETHER_TYPE_LEN > frame + length) { ++ AP6211_DEBUG("%s: short VLAN frame (%d)\n", __FUNCTION__, length); ++ return DHD_PKT_FRAG_NONE; ++ } ++ ++ ethertype = ntoh16(*(uint16 *)pt); ++ } ++ ++ if (ethertype != ETHER_TYPE_IP) { ++ AP6211_DEBUG("%s: non-IP frame (ethertype 0x%x, length %d)\n", ++ __FUNCTION__, ethertype, length); ++ return DHD_PKT_FRAG_NONE; ++ } ++ ++ iph = (struct ipv4_hdr *)(pt + ETHER_TYPE_LEN); ++ ipl = length - (pt + ETHER_TYPE_LEN - frame); ++ ++ /* We support IPv4 only */ ++ if ((ipl < IPV4_OPTIONS_OFFSET) || (IP_VER(iph) != IP_VER_4)) { ++ AP6211_DEBUG("%s: short frame (%d) or non-IPv4\n", __FUNCTION__, ipl); ++ return DHD_PKT_FRAG_NONE; ++ } ++ ++ iph_frag = ntoh16(iph->frag); ++ ++ if (iph_frag & IPV4_FRAG_DONT) { ++ return DHD_PKT_FRAG_NONE; ++ } else if ((iph_frag & IPV4_FRAG_MORE) == 0) { ++ return DHD_PKT_FRAG_LAST; ++ } else { ++ return (iph_frag & IPV4_FRAG_OFFSET_MASK)? DHD_PKT_FRAG_CONT : DHD_PKT_FRAG_FIRST; ++ } ++} +diff --git a/drivers/net/wireless/ap6211/dhd_ip.h b/drivers/net/wireless/ap6211/dhd_ip.h +new file mode 100755 +index 0000000..ceb3877 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_ip.h +@@ -0,0 +1,42 @@ ++/* ++ * Header file describing the common ip parser function. ++ * ++ * Provides type definitions and function prototypes used to parse ip packet. ++ * ++ * Copyright (C) 1999-2013, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id$ ++ */ ++ ++#ifndef _dhd_ip_h_ ++#define _dhd_ip_h_ ++ ++typedef enum pkt_frag ++{ ++ DHD_PKT_FRAG_NONE = 0, ++ DHD_PKT_FRAG_FIRST, ++ DHD_PKT_FRAG_CONT, ++ DHD_PKT_FRAG_LAST ++} pkt_frag_t; ++ ++extern pkt_frag_t pkt_frag_info(osl_t *osh, void *p); ++ ++#endif /* _dhd_ip_h_ */ +diff --git a/drivers/net/wireless/ap6211/dhd_linux.c b/drivers/net/wireless/ap6211/dhd_linux.c +new file mode 100755 +index 0000000..28fe811 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_linux.c +@@ -0,0 +1,6152 @@ ++/* ++ * Broadcom Dongle Host Driver (DHD), Linux-specific network interface ++ * Basically selected code segments from usb-cdc.c and usb-rndis.c ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_linux.c 374275 2012-12-12 11:44:18Z $ ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_HAS_WAKELOCK ++#include ++#endif ++#ifdef WL_CFG80211 ++#include ++#endif ++ ++#ifdef WLBTAMP ++#include ++#include ++#include ++#endif ++ ++#include ++#include ++ ++#ifdef WLMEDIA_HTSF ++#include ++#include ++ ++#define HTSF_MINLEN 200 /* min. packet length to timestamp */ ++#define HTSF_BUS_DELAY 150 /* assume a fix propagation in us */ ++#define TSMAX 1000 /* max no. of timing record kept */ ++#define NUMBIN 34 ++static uint32 tsidx = 0; ++static uint32 htsf_seqnum = 0; ++uint32 tsfsync; ++struct timeval tsync; ++static uint32 tsport = 5010; ++ ++typedef struct histo_ { ++ uint32 bin[NUMBIN]; ++} histo_t; ++ ++#if !ISPOWEROF2(DHD_SDALIGN) ++#error DHD_SDALIGN is not a power of 2! ++#endif ++ ++static histo_t vi_d1, vi_d2, vi_d3, vi_d4; ++#endif /* WLMEDIA_HTSF */ ++ ++#if defined(PKT_FILTER_SUPPORT) ++#endif /* PKT_FILTER_SUPPORT */ ++ ++#if defined(SOFTAP) ++extern bool ap_cfg_running; ++extern bool ap_fw_loaded; ++#endif ++ ++/* enable HOSTIP cache update from the host side when an eth0:N is up */ ++#define AOE_IP_ALIAS_SUPPORT 1 ++ ++#ifdef BCM_FD_AGGR ++#include ++#include ++#endif ++#ifdef PROP_TXSTATUS ++#include ++#include ++#endif ++ ++#include ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx); ++static int dhd_device_event(struct notifier_block *this, ++ unsigned long event, ++ void *ptr); ++ ++static struct notifier_block dhd_notifier = { ++ .notifier_call = dhd_device_event ++}; ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) ++#include ++volatile bool dhd_mmc_suspend = FALSE; ++DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ ++ ++#if defined(OOB_INTR_ONLY) ++extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1) ++static void dhd_hang_process(struct work_struct *work); ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++MODULE_LICENSE("GPL v2"); ++#endif /* LinuxVer */ ++ ++#include ++ ++#ifdef BCM_FD_AGGR ++#define DBUS_RX_BUFFER_SIZE_DHD(net) (BCM_RPC_TP_DNGL_AGG_MAX_BYTE) ++#else ++#ifndef PROP_TXSTATUS ++#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen) ++#else ++#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128) ++#endif ++#endif /* BCM_FD_AGGR */ ++ ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) ++const char * ++print_tainted() ++{ ++ return ""; ++} ++#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */ ++ ++/* Linux wireless extension support */ ++#if defined(CONFIG_WIRELESS_EXT) ++#include ++extern wl_iw_extra_params_t g_wl_iw_params; ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++#include ++#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ ++ ++extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); ++ ++#ifdef PKT_FILTER_SUPPORT ++extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); ++extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); ++#endif ++ ++#ifdef READ_MACADDR ++extern int dhd_read_macaddr(struct dhd_info *dhd, struct ether_addr *mac); ++#endif ++#ifdef RDWR_MACADDR ++extern int dhd_check_rdwr_macaddr(struct dhd_info *dhd, dhd_pub_t *dhdp, struct ether_addr *mac); ++extern int dhd_write_rdwr_macaddr(struct ether_addr *mac); ++#endif ++#ifdef WRITE_MACADDR ++extern int dhd_write_macaddr(struct ether_addr *mac); ++#endif ++#ifdef GET_MAC_FROM_OTP ++extern int dhd_check_module_mac(dhd_pub_t *dhd, struct ether_addr *mac); ++#endif ++#ifdef MIMO_ANT_SETTING ++extern int dhd_sel_ant_from_file(dhd_pub_t *dhd); ++#endif ++ ++#ifdef GLOBALCONFIG_WLAN_COUNTRY_CODE ++int dhd_customer_set_country(dhd_pub_t *dhd); ++#endif ++ ++/* Interface control information */ ++typedef struct dhd_if { ++ struct dhd_info *info; /* back pointer to dhd_info */ ++ /* OS/stack specifics */ ++ struct net_device *net; ++ struct net_device_stats stats; ++ int idx; /* iface idx in dongle */ ++ dhd_if_state_t state; /* interface state */ ++ uint subunit; /* subunit */ ++ uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */ ++ bool attached; /* Delayed attachment when unset */ ++ bool txflowcontrol; /* Per interface flow control indicator */ ++ char name[IFNAMSIZ+1]; /* linux interface name */ ++ uint8 bssidx; /* bsscfg index for the interface */ ++ bool set_multicast; ++ bool event2cfg80211; /* To determine if pass event to cfg80211 */ ++} dhd_if_t; ++ ++#ifdef WLMEDIA_HTSF ++typedef struct { ++ uint32 low; ++ uint32 high; ++} tsf_t; ++ ++typedef struct { ++ uint32 last_cycle; ++ uint32 last_sec; ++ uint32 last_tsf; ++ uint32 coef; /* scaling factor */ ++ uint32 coefdec1; /* first decimal */ ++ uint32 coefdec2; /* second decimal */ ++} htsf_t; ++ ++typedef struct { ++ uint32 t1; ++ uint32 t2; ++ uint32 t3; ++ uint32 t4; ++} tstamp_t; ++ ++static tstamp_t ts[TSMAX]; ++static tstamp_t maxdelayts; ++static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0; ++ ++#endif /* WLMEDIA_HTSF */ ++ ++/* Local private structure (extension of pub) */ ++typedef struct dhd_info { ++#if defined(CONFIG_WIRELESS_EXT) ++ wl_iw_t iw; /* wireless extensions state (must be first) */ ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++ dhd_pub_t pub; ++ ++ /* For supporting multiple interfaces */ ++ dhd_if_t *iflist[DHD_MAX_IFS]; ++ ++ struct semaphore proto_sem; ++#ifdef PROP_TXSTATUS ++ spinlock_t wlfc_spinlock; ++#endif /* PROP_TXSTATUS */ ++#ifdef WLMEDIA_HTSF ++ htsf_t htsf; ++#endif ++ wait_queue_head_t ioctl_resp_wait; ++ struct timer_list timer; ++ bool wd_timer_valid; ++ struct tasklet_struct tasklet; ++ spinlock_t sdlock; ++ spinlock_t txqlock; ++ spinlock_t dhd_lock; ++#ifdef DHDTHREAD ++ /* Thread based operation */ ++ bool threads_only; ++ struct semaphore sdsem; ++ ++ tsk_ctl_t thr_dpc_ctl; ++ tsk_ctl_t thr_wdt_ctl; ++#endif /* DHDTHREAD */ ++ bool dhd_tasklet_create; ++ tsk_ctl_t thr_sysioc_ctl; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ struct work_struct work_hang; ++#endif ++ ++ /* Wakelocks */ ++#if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ struct wake_lock *wl_wifi; /* Wifi wakelock */ ++ struct wake_lock *wl_rxwake; /* Wifi rx wakelock */ ++ struct wake_lock *wl_ctrlwake; /* Wifi ctrl wakelock */ ++ struct wake_lock *wl_wdwake; /* Wifi wd wakelock */ ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ /* net_device interface lock, prevent race conditions among net_dev interface ++ * calls and wifi_on or wifi_off ++ */ ++ struct mutex dhd_net_if_mutex; ++ struct mutex dhd_suspend_mutex; ++#endif ++ spinlock_t wakelock_spinlock; ++ int wakelock_counter; ++ int wakelock_wd_counter; ++ int wakelock_rx_timeout_enable; ++ int wakelock_ctrl_timeout_enable; ++ ++ /* Thread to issue ioctl for multicast */ ++ unsigned char set_macaddress; ++ struct ether_addr macvalue; ++ wait_queue_head_t ctrl_wait; ++ atomic_t pend_8021x_cnt; ++ dhd_attach_states_t dhd_state; ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++ struct early_suspend early_suspend; ++#endif /* CONFIG_HAS_EARLYSUSPEND && defined(DHD_USE_EARLYSUSPEND) */ ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ u32 pend_ipaddr; ++#endif /* ARP_OFFLOAD_SUPPORT */ ++#ifdef BCM_FD_AGGR ++ void *rpc_th; ++ void *rpc_osh; ++ struct timer_list rpcth_timer; ++ bool rpcth_timer_active; ++ bool fdaggr; ++#endif ++} dhd_info_t; ++ ++/* Flag to indicate if we should download firmware on driver load */ ++uint dhd_download_fw_on_driverload = TRUE; ++ ++/* Definitions to provide path to the firmware and nvram ++ * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt" ++ */ ++char firmware_path[MOD_PARAM_PATHLEN]; ++char nvram_path[MOD_PARAM_PATHLEN]; ++ ++/* information string to keep firmware, chio, cheip version info visiable from log */ ++char info_string[MOD_PARAM_INFOLEN]; ++module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444); ++ ++int op_mode = 0; ++int disable_proptx = 0; ++module_param(op_mode, int, 0644); ++extern int wl_control_wl_start(struct net_device *dev); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++struct semaphore dhd_registration_sem; ++struct semaphore dhd_chipup_sem; ++int dhd_registration_check = FALSE; ++ ++#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++ ++/* Spawn a thread for system ioctls (set mac, set mcast) */ ++uint dhd_sysioc = TRUE; ++module_param(dhd_sysioc, uint, 0); ++ ++/* Error bits */ ++module_param(dhd_msg_level, int, 0); ++#if defined(CONFIG_WIRELESS_EXT) ++module_param(iw_msg_level, int, 0); ++#endif ++#ifdef WL_CFG80211 ++module_param(wl_dbg_level, int, 0); ++#endif ++//module_param(android_msg_level, int, 0); ++ ++/* Disable Prop tx */ ++module_param(disable_proptx, int, 0644); ++ ++/* load firmware and/or nvram values from the filesystem */ ++module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660); ++module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0); ++ ++/* Watchdog interval */ ++uint dhd_watchdog_ms = 10; ++module_param(dhd_watchdog_ms, uint, 0); ++ ++#if defined(DHD_DEBUG) ++/* Console poll interval */ ++uint dhd_console_ms = 0; ++module_param(dhd_console_ms, uint, 0644); ++#endif /* defined(DHD_DEBUG) */ ++ ++uint dhd_slpauto = TRUE; ++module_param(dhd_slpauto, uint, 0); ++ ++/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */ ++uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY; ++module_param(dhd_arp_mode, uint, 0); ++ ++/* ARP offload enable */ ++uint dhd_arp_enable = TRUE; ++module_param(dhd_arp_enable, uint, 0); ++ ++#ifdef PKT_FILTER_SUPPORT ++/* Global Pkt filter enable control */ ++uint dhd_pkt_filter_enable = TRUE; ++module_param(dhd_pkt_filter_enable, uint, 0); ++#endif ++ ++/* Pkt filter init setup */ ++uint dhd_pkt_filter_init = 0; ++module_param(dhd_pkt_filter_init, uint, 0); ++ ++/* Pkt filter mode control */ ++#ifdef GAN_LITE_NAT_KEEPALIVE_FILTER ++uint dhd_master_mode = FALSE; ++#else ++uint dhd_master_mode = TRUE; ++#endif /* GAL_LITE_NAT_KEEPALIVE_FILTER */ ++module_param(dhd_master_mode, uint, 0); ++ ++#ifdef DHDTHREAD ++int dhd_watchdog_prio = 0; ++module_param(dhd_watchdog_prio, int, 0); ++ ++/* DPC thread priority */ ++int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING; ++module_param(dhd_dpc_prio, int, 0); ++ ++/* DPC thread priority, -1 to use tasklet */ ++extern int dhd_dongle_memsize; ++module_param(dhd_dongle_memsize, int, 0); ++#endif /* DHDTHREAD */ ++/* Control fw roaming */ ++uint dhd_roam_disable = 0; ++ ++/* Control radio state */ ++uint dhd_radio_up = 1; ++ ++/* Network inteface name */ ++char iface_name[IFNAMSIZ] = {'\0'}; ++module_param_string(iface_name, iface_name, IFNAMSIZ, 0); ++ ++/* The following are specific to the SDIO dongle */ ++ ++/* IOCTL response timeout */ ++int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT; ++ ++/* Idle timeout for backplane clock */ ++int dhd_idletime = DHD_IDLETIME_TICKS; ++module_param(dhd_idletime, int, 0); ++ ++/* Use polling */ ++uint dhd_poll = FALSE; ++module_param(dhd_poll, uint, 0); ++ ++/* Use interrupts */ ++uint dhd_intr = TRUE; ++module_param(dhd_intr, uint, 0); ++ ++/* SDIO Drive Strength (in milliamps) */ ++uint dhd_sdiod_drive_strength = 6; ++module_param(dhd_sdiod_drive_strength, uint, 0); ++ ++/* Tx/Rx bounds */ ++extern uint dhd_txbound; ++extern uint dhd_rxbound; ++module_param(dhd_txbound, uint, 0); ++module_param(dhd_rxbound, uint, 0); ++ ++/* Deferred transmits */ ++extern uint dhd_deferred_tx; ++module_param(dhd_deferred_tx, uint, 0); ++ ++#ifdef BCMDBGFS ++extern void dhd_dbg_init(dhd_pub_t *dhdp); ++extern void dhd_dbg_remove(void); ++#endif /* BCMDBGFS */ ++ ++/* ++ * the the 2 vars init at init time ++ *benn@cubietech.com ++ */ ++#define WL_HOST_WAKE_DEF_GPIO 86 ++int wl_host_wake_irqno = -1; ++int wl_host_wake = -1; ++ ++ ++#ifdef SDTEST ++/* Echo packet generator (pkts/s) */ ++uint dhd_pktgen = 0; ++module_param(dhd_pktgen, uint, 0); ++ ++/* Echo packet len (0 => sawtooth, max 2040) */ ++uint dhd_pktgen_len = 0; ++module_param(dhd_pktgen_len, uint, 0); ++#endif /* SDTEST */ ++ ++/* Version string to report */ ++#ifdef DHD_DEBUG ++#ifndef SRCBASE ++#define SRCBASE "drivers/net/wireless/ap6211" ++#endif ++#define DHD_COMPILED "\nCompiled in " SRCBASE ++#else ++#define DHD_COMPILED ++#endif /* DHD_DEBUG */ ++ ++static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "."; ++#ifdef DHD_DEBUG ++static char dhd_version_info[] = "Compiled in " SRCBASE " on " __DATE__ " at " __TIME__ "."; ++#endif ++ ++static void dhd_net_if_lock_local(dhd_info_t *dhd); ++static void dhd_net_if_unlock_local(dhd_info_t *dhd); ++static void dhd_suspend_lock(dhd_pub_t *dhdp); ++static void dhd_suspend_unlock(dhd_pub_t *dhdp); ++ ++#ifdef WLMEDIA_HTSF ++void htsf_update(dhd_info_t *dhd, void *data); ++tsf_t prev_tsf, cur_tsf; ++ ++uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx); ++static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx); ++static void dhd_dump_latency(void); ++static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf); ++static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf); ++static void dhd_dump_htsfhisto(histo_t *his, char *s); ++#endif /* WLMEDIA_HTSF */ ++ ++/* Monitor interface */ ++int dhd_monitor_init(void *dhd_pub); ++int dhd_monitor_uninit(void); ++ ++ ++#if defined(CONFIG_WIRELESS_EXT) ++struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++static void dhd_dpc(ulong data); ++/* forward decl */ ++extern int dhd_wait_pend8021x(struct net_device *dev); ++ ++#ifdef TOE ++#ifndef BDC ++#error TOE requires BDC ++#endif /* !BDC */ ++static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol); ++static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); ++#endif /* TOE */ ++ ++static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, ++ wl_event_msg_t *event_ptr, void **data_ptr); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) ++static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) ++{ ++ int ret = NOTIFY_DONE; ++ ++#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) || (LINUX_VERSION_CODE <= \ ++ KERNEL_VERSION(2, 6, 39)) ++ switch (action) { ++ case PM_HIBERNATION_PREPARE: ++ case PM_SUSPEND_PREPARE: ++ dhd_mmc_suspend = TRUE; ++ ret = NOTIFY_OK; ++ break; ++ case PM_POST_HIBERNATION: ++ case PM_POST_SUSPEND: ++ dhd_mmc_suspend = FALSE; ++ ret = NOTIFY_OK; ++ break; ++ } ++ smp_mb(); ++#endif ++ return ret; ++} ++ ++static struct notifier_block dhd_sleep_pm_notifier = { ++ .notifier_call = dhd_sleep_pm_callback, ++ .priority = 10 ++}; ++extern int register_pm_notifier(struct notifier_block *nb); ++extern int unregister_pm_notifier(struct notifier_block *nb); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ ++ ++void dhd_set_packet_filter(dhd_pub_t *dhd) ++{ ++#ifdef PKT_FILTER_SUPPORT ++ int i; ++ ++ AP6211_DEBUG("%s: enter\n", __FUNCTION__); ++ if (dhd_pkt_filter_enable) { ++ for (i = 0; i < dhd->pktfilter_count; i++) { ++ dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); ++ } ++ } ++#endif /* PKT_FILTER_SUPPORT */ ++} ++ ++void dhd_enable_packet_filter(int value, dhd_pub_t *dhd) ++{ ++#ifdef PKT_FILTER_SUPPORT ++ int i; ++ ++ AP6211_DEBUG("%s: enter, value = %d\n", __FUNCTION__, value); ++ /* 1 - Enable packet filter, only allow unicast packet to send up */ ++ /* 0 - Disable packet filter */ ++ if (dhd_pkt_filter_enable && (!value || ++ (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress))) { ++ for (i = 0; i < dhd->pktfilter_count; i++) { ++#ifdef PASS_ARP_PACKET ++ if (value && (i == dhd->pktfilter_count -1) && ++ !(dhd->op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) { ++ AP6211_DEBUG("Do not turn on ARP white list pkt filter:" ++ "val %d, cnt %d, op_mode 0x%x\n", ++ value, i, dhd->op_mode); ++ continue; ++ } ++#endif ++ dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], ++ value, dhd_master_mode); ++ } ++ } ++#endif /* PKT_FILTER_SUPPORT */ ++} ++ ++static int dhd_set_suspend(int value, dhd_pub_t *dhd) ++{ ++#if !defined(SUPPORT_PM2_ONLY) ++ int power_mode = PM_MAX; ++#endif ++ /* wl_pkt_filter_enable_t enable_parm; */ ++ char iovbuf[32]; ++ int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */ ++#ifndef DISABLE_FW_ROAM_SUSPEND ++ uint roamvar = 1; ++#endif ++#ifdef ENABLE_BCN_LI_BCN_WAKEUP ++ int bcn_li_bcn; ++#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ ++#ifdef PASS_ALL_MCAST_PKTS ++ struct dhd_info *dhdinfo = dhd->info; ++ uint32 allmulti; ++ uint i; ++#endif /* PASS_ALL_MCAST_PKTS */ ++ ++ AP6211_DEBUG("%s: enter, value = %d in_suspend=%d\n", ++ __FUNCTION__, value, dhd->in_suspend); ++ ++ dhd_suspend_lock(dhd); ++ if (dhd && dhd->up) { ++ if (value && dhd->in_suspend) { ++#ifdef PKT_FILTER_SUPPORT ++ dhd->early_suspended = 1; ++#endif ++ /* Kernel suspended */ ++ AP6211_ERR("%s: force extra Suspend setting\n", __FUNCTION__); ++ ++#if !defined(SUPPORT_PM2_ONLY) ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, ++ sizeof(power_mode), TRUE, 0); ++#endif ++ /* Enable packet filter, only allow unicast packet to send up */ ++ dhd_enable_packet_filter(1, dhd); ++#ifdef PASS_ALL_MCAST_PKTS ++ allmulti = 0; ++ bcm_mkiovar("allmulti", (char *)&allmulti, ++ 4, iovbuf, sizeof(iovbuf)); ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net) ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, ++ sizeof(iovbuf), TRUE, i); ++ } ++#endif /* PASS_ALL_MCAST_PKTS */ ++ ++ /* If DTIM skip is set up as default, force it to wake ++ * each third DTIM for better power savings. Note that ++ * one side effect is a chance to miss BC/MC packet. ++ */ ++ bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd); ++ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, ++ 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ ++#ifndef DISABLE_FW_ROAM_SUSPEND ++ /* Disable firmware roaming during suspend */ ++ bcm_mkiovar("roam_off", (char *)&roamvar, 4, ++ iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#endif ++#ifdef ENABLE_BCN_LI_BCN_WAKEUP ++ bcn_li_bcn = 0; ++ bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, ++ 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ ++ ++ } else { ++#ifdef PKT_FILTER_SUPPORT ++ dhd->early_suspended = 0; ++#endif ++ /* Kernel resumed */ ++ AP6211_ERR("%s: Remove extra suspend setting\n", __FUNCTION__); ++ ++#if !defined(SUPPORT_PM2_ONLY) ++ power_mode = PM_FAST; ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, ++ sizeof(power_mode), TRUE, 0); ++#endif ++ /* disable pkt filter */ ++ dhd_enable_packet_filter(0, dhd); ++#ifdef PASS_ALL_MCAST_PKTS ++ allmulti = 1; ++ bcm_mkiovar("allmulti", (char *)&allmulti, ++ 4, iovbuf, sizeof(iovbuf)); ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net) ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, ++ sizeof(iovbuf), TRUE, i); ++ } ++#endif /* PASS_ALL_MCAST_PKTS */ ++ ++ /* restore pre-suspend setting for dtim_skip */ ++ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, ++ 4, iovbuf, sizeof(iovbuf)); ++ ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#ifndef DISABLE_FW_ROAM_SUSPEND ++ roamvar = dhd_roam_disable; ++ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, ++ sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#endif ++#ifdef ENABLE_BCN_LI_BCN_WAKEUP ++ bcn_li_bcn = 1; ++ bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, ++ 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ ++ ++ } ++ } ++ ++ dhd_suspend_unlock(dhd); ++ return 0; ++} ++ ++static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force) ++{ ++ dhd_pub_t *dhdp = &dhd->pub; ++ int ret = 0; ++ ++ DHD_OS_WAKE_LOCK(dhdp); ++ /* Set flag when early suspend was called */ ++ dhdp->in_suspend = val; ++ if ((force || !dhdp->suspend_disable_flag) && ++ dhd_support_sta_mode(dhdp)) ++ { ++ ret = dhd_set_suspend(val, dhdp); ++ } ++ ++ DHD_OS_WAKE_UNLOCK(dhdp); ++ return ret; ++} ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++static void dhd_early_suspend(struct early_suspend *h) ++{ ++ struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); ++ AP6211_DEBUG("%s: enter\n", __FUNCTION__); ++ ++ if (dhd) ++ dhd_suspend_resume_helper(dhd, 1, 0); ++} ++ ++static void dhd_late_resume(struct early_suspend *h) ++{ ++ struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); ++ AP6211_DEBUG("%s: enter\n", __FUNCTION__); ++ ++ if (dhd) ++ dhd_suspend_resume_helper(dhd, 0, 0); ++} ++#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ ++ ++/* ++ * Generalized timeout mechanism. Uses spin sleep with exponential back-off until ++ * the sleep time reaches one jiffy, then switches over to task delay. Usage: ++ * ++ * dhd_timeout_start(&tmo, usec); ++ * while (!dhd_timeout_expired(&tmo)) ++ * if (poll_something()) ++ * break; ++ * if (dhd_timeout_expired(&tmo)) ++ * fatal(); ++ */ ++ ++void ++dhd_timeout_start(dhd_timeout_t *tmo, uint usec) ++{ ++ tmo->limit = usec; ++ tmo->increment = 0; ++ tmo->elapsed = 0; ++ tmo->tick = jiffies_to_usecs(1); ++} ++ ++int ++dhd_timeout_expired(dhd_timeout_t *tmo) ++{ ++ /* Does nothing the first call */ ++ if (tmo->increment == 0) { ++ tmo->increment = 1; ++ return 0; ++ } ++ ++ if (tmo->elapsed >= tmo->limit) ++ return 1; ++ ++ /* Add the delay that's about to take place */ ++ tmo->elapsed += tmo->increment; ++ ++ if (tmo->increment < tmo->tick) { ++ OSL_DELAY(tmo->increment); ++ tmo->increment *= 2; ++ if (tmo->increment > tmo->tick) ++ tmo->increment = tmo->tick; ++ } else { ++ wait_queue_head_t delay_wait; ++ DECLARE_WAITQUEUE(wait, current); ++ init_waitqueue_head(&delay_wait); ++ add_wait_queue(&delay_wait, &wait); ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(1); ++ remove_wait_queue(&delay_wait, &wait); ++ set_current_state(TASK_RUNNING); ++ } ++ ++ return 0; ++} ++ ++int ++dhd_net2idx(dhd_info_t *dhd, struct net_device *net) ++{ ++ int i = 0; ++ ++ ASSERT(dhd); ++ while (i < DHD_MAX_IFS) { ++ if (dhd->iflist[i] && (dhd->iflist[i]->net == net)) ++ return i; ++ i++; ++ } ++ ++ return DHD_BAD_IF; ++} ++ ++struct net_device * dhd_idx2net(void *pub, int ifidx) ++{ ++ struct dhd_pub *dhd_pub = (struct dhd_pub *)pub; ++ struct dhd_info *dhd_info; ++ ++ if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS) ++ return NULL; ++ dhd_info = dhd_pub->info; ++ if (dhd_info && dhd_info->iflist[ifidx]) ++ return dhd_info->iflist[ifidx]->net; ++ return NULL; ++} ++ ++int ++dhd_ifname2idx(dhd_info_t *dhd, char *name) ++{ ++ int i = DHD_MAX_IFS; ++ ++ ASSERT(dhd); ++ ++ if (name == NULL || *name == '\0') ++ return 0; ++ ++ while (--i > 0) ++ if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ)) ++ break; ++ ++ AP6211_DEBUG("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name); ++ ++ return i; /* default - the primary interface */ ++} ++ ++char * ++dhd_ifname(dhd_pub_t *dhdp, int ifidx) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ ++ ASSERT(dhd); ++ ++ if (ifidx < 0 || ifidx >= DHD_MAX_IFS) { ++ AP6211_ERR("%s: ifidx %d out of range\n", __FUNCTION__, ifidx); ++ return ""; ++ } ++ ++ if (dhd->iflist[ifidx] == NULL) { ++ AP6211_ERR("%s: null i/f %d\n", __FUNCTION__, ifidx); ++ return ""; ++ } ++ ++ if (dhd->iflist[ifidx]->net) ++ return dhd->iflist[ifidx]->net->name; ++ ++ return ""; ++} ++ ++uint8 * ++dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx) ++{ ++ int i; ++ dhd_info_t *dhd = (dhd_info_t *)dhdp; ++ ++ ASSERT(dhd); ++ for (i = 0; i < DHD_MAX_IFS; i++) ++ if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx) ++ return dhd->iflist[i]->mac_addr; ++ ++ return NULL; ++} ++ ++ ++static void ++_dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) ++{ ++ struct net_device *dev; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) ++ struct netdev_hw_addr *ha; ++#else ++ struct dev_mc_list *mclist; ++#endif ++ uint32 allmulti, cnt; ++ ++ wl_ioctl_t ioc; ++ char *buf, *bufp; ++ uint buflen; ++ int ret; ++ ++ ASSERT(dhd && dhd->iflist[ifidx]); ++ dev = dhd->iflist[ifidx]->net; ++ if (!dev) ++ return; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++ netif_addr_lock_bh(dev); ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) ++ cnt = netdev_mc_count(dev); ++#else ++ cnt = dev->mc_count; ++#endif /* LINUX_VERSION_CODE */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++ netif_addr_unlock_bh(dev); ++#endif ++ ++ /* Determine initial value of allmulti flag */ ++ allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; ++#ifdef PASS_ALL_MCAST_PKTS ++#ifdef PKT_FILTER_SUPPORT ++ if (!dhd->pub.early_suspended) ++#endif /* PKT_FILTER_SUPPORT */ ++ allmulti = TRUE; ++#endif /* PASS_ALL_MCAST_PKTS */ ++ ++ /* Send down the multicast list first. */ ++ ++ ++ buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN); ++ if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) { ++ AP6211_ERR("%s: out of memory for mcast_list, cnt %d\n", ++ dhd_ifname(&dhd->pub, ifidx), cnt); ++ return; ++ } ++ ++ strncpy(bufp, "mcast_list", buflen - 1); ++ bufp[buflen - 1] = '\0'; ++ bufp += strlen("mcast_list") + 1; ++ ++ cnt = htol32(cnt); ++ memcpy(bufp, &cnt, sizeof(cnt)); ++ bufp += sizeof(cnt); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++ netif_addr_lock_bh(dev); ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) ++ netdev_for_each_mc_addr(ha, dev) { ++ if (!cnt) ++ break; ++ memcpy(bufp, ha->addr, ETHER_ADDR_LEN); ++ bufp += ETHER_ADDR_LEN; ++ cnt--; ++ } ++#else ++ for (mclist = dev->mc_list; (mclist && (cnt > 0)); ++ cnt--, mclist = mclist->next) { ++ memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); ++ bufp += ETHER_ADDR_LEN; ++ } ++#endif /* LINUX_VERSION_CODE */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++ netif_addr_unlock_bh(dev); ++#endif ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ioc.cmd = WLC_SET_VAR; ++ ioc.buf = buf; ++ ioc.len = buflen; ++ ioc.set = TRUE; ++ ++ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); ++ if (ret < 0) { ++ AP6211_ERR("%s: set mcast_list failed, cnt %d\n", ++ dhd_ifname(&dhd->pub, ifidx), cnt); ++ allmulti = cnt ? TRUE : allmulti; ++ } ++ ++ MFREE(dhd->pub.osh, buf, buflen); ++ ++ /* Now send the allmulti setting. This is based on the setting in the ++ * net_device flags, but might be modified above to be turned on if we ++ * were trying to set some addresses and dongle rejected it... ++ */ ++ ++ buflen = sizeof("allmulti") + sizeof(allmulti); ++ if (!(buf = MALLOC(dhd->pub.osh, buflen))) { ++ AP6211_ERR("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx)); ++ return; ++ } ++ allmulti = htol32(allmulti); ++ ++ if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) { ++ AP6211_ERR("%s: mkiovar failed for allmulti, datalen %d buflen %u\n", ++ dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen); ++ MFREE(dhd->pub.osh, buf, buflen); ++ return; ++ } ++ ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ioc.cmd = WLC_SET_VAR; ++ ioc.buf = buf; ++ ioc.len = buflen; ++ ioc.set = TRUE; ++ ++ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); ++ if (ret < 0) { ++ AP6211_ERR("%s: set allmulti %d failed\n", ++ dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)); ++ } ++ ++ MFREE(dhd->pub.osh, buf, buflen); ++ ++ /* Finally, pick up the PROMISC flag as well, like the NIC driver does */ ++ ++ allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE; ++ allmulti = htol32(allmulti); ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ioc.cmd = WLC_SET_PROMISC; ++ ioc.buf = &allmulti; ++ ioc.len = sizeof(allmulti); ++ ioc.set = TRUE; ++ ++ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); ++ if (ret < 0) { ++ AP6211_ERR("%s: set promisc %d failed\n", ++ dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)); ++ } ++} ++ ++int ++_dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr) ++{ ++ char buf[32]; ++ wl_ioctl_t ioc; ++ int ret; ++ ++ if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) { ++ AP6211_ERR("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx)); ++ return -1; ++ } ++ memset(&ioc, 0, sizeof(ioc)); ++ ioc.cmd = WLC_SET_VAR; ++ ioc.buf = buf; ++ ioc.len = 32; ++ ioc.set = TRUE; ++ ++ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); ++ if (ret < 0) { ++ AP6211_ERR("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx)); ++ } else { ++ memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN); ++ memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN); ++ } ++ ++ return ret; ++} ++ ++#ifdef SOFTAP ++extern struct net_device *ap_net_dev; ++extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */ ++#endif ++ ++static void ++dhd_op_if(dhd_if_t *ifp) ++{ ++ dhd_info_t *dhd; ++ int ret = 0, err = 0; ++#ifdef SOFTAP ++ unsigned long flags; ++#endif ++ ++ if (!ifp || !ifp->info || !ifp->idx) ++ return; ++ ASSERT(ifp && ifp->info && ifp->idx); /* Virtual interfaces only */ ++ dhd = ifp->info; ++ ++ AP6211_DEBUG("%s: idx %d, state %d\n", __FUNCTION__, ifp->idx, ifp->state); ++ ++#ifdef WL_CFG80211 ++ if (wl_cfg80211_is_progress_ifchange()) ++ return; ++ ++#endif ++ switch (ifp->state) { ++ case DHD_IF_ADD: ++ /* ++ * Delete the existing interface before overwriting it ++ * in case we missed the WLC_E_IF_DEL event. ++ */ ++ if (ifp->net != NULL) { ++ AP6211_ERR("%s: ERROR: netdev:%s already exists, try free & unregister \n", ++ __FUNCTION__, ifp->net->name); ++ netif_stop_queue(ifp->net); ++ unregister_netdev(ifp->net); ++ free_netdev(ifp->net); ++ } ++ /* Allocate etherdev, including space for private structure */ ++ if (!(ifp->net = alloc_etherdev(sizeof(dhd)))) { ++ AP6211_ERR("%s: OOM - alloc_etherdev\n", __FUNCTION__); ++ ret = -ENOMEM; ++ } ++ if (ret == 0) { ++ strncpy(ifp->net->name, ifp->name, IFNAMSIZ); ++ ifp->net->name[IFNAMSIZ - 1] = '\0'; ++ memcpy(netdev_priv(ifp->net), &dhd, sizeof(dhd)); ++#ifdef WL_CFG80211 ++ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) ++ if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx, ++ (void*)dhd_net_attach)) { ++ ifp->state = DHD_IF_NONE; ++ ifp->event2cfg80211 = TRUE; ++ return; ++ } ++#endif ++ if ((err = dhd_net_attach(&dhd->pub, ifp->idx)) != 0) { ++ AP6211_ERR("%s: dhd_net_attach failed, err %d\n", ++ __FUNCTION__, err); ++ ret = -EOPNOTSUPP; ++ } else { ++#if defined(SOFTAP) ++ if (ap_fw_loaded && !(dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { ++ /* semaphore that the soft AP CODE waits on */ ++ flags = dhd_os_spin_lock(&dhd->pub); ++ ++ /* save ptr to wl0.1 netdev for use in wl_iw.c */ ++ ap_net_dev = ifp->net; ++ /* signal to the SOFTAP 'sleeper' thread, wl0.1 is ready */ ++ up(&ap_eth_ctl.sema); ++ dhd_os_spin_unlock(&dhd->pub, flags); ++ } ++#endif ++ AP6211_DEBUG(" ==== pid:%x, net_device for if:%s created ===\n\n", ++ current->pid, ifp->net->name); ++ ifp->state = DHD_IF_NONE; ++ } ++ } ++ break; ++ case DHD_IF_DEL: ++ /* Make sure that we don't enter again here if .. */ ++ /* dhd_op_if is called again from some other context */ ++ ifp->state = DHD_IF_DELETING; ++ if (ifp->net != NULL) { ++ AP6211_DEBUG("%s: got 'DHD_IF_DEL' state\n", __FUNCTION__); ++ netif_stop_queue(ifp->net); ++#ifdef WL_CFG80211 ++ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { ++ wl_cfg80211_ifdel_ops(ifp->net); ++ } ++#endif ++ unregister_netdev(ifp->net); ++ ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */ ++#ifdef WL_CFG80211 ++ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { ++ wl_cfg80211_notify_ifdel(); ++ } ++#endif ++ } ++ break; ++ case DHD_IF_DELETING: ++ break; ++ default: ++ AP6211_ERR("%s: bad op %d\n", __FUNCTION__, ifp->state); ++ ASSERT(!ifp->state); ++ break; ++ } ++ ++ if (ret < 0) { ++ ifp->set_multicast = FALSE; ++ if (ifp->net) { ++ free_netdev(ifp->net); ++ ifp->net = NULL; ++ } ++ dhd->iflist[ifp->idx] = NULL; ++#ifdef SOFTAP ++ flags = dhd_os_spin_lock(&dhd->pub); ++ if (ifp->net == ap_net_dev) ++ ap_net_dev = NULL; /* NULL SOFTAP global wl0.1 as well */ ++ dhd_os_spin_unlock(&dhd->pub, flags); ++#endif /* SOFTAP */ ++ MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); ++ } ++} ++ ++static int ++_dhd_sysioc_thread(void *data) ++{ ++ tsk_ctl_t *tsk = (tsk_ctl_t *)data; ++ dhd_info_t *dhd = (dhd_info_t *)tsk->parent; ++ ++ ++ int i; ++#ifdef SOFTAP ++ bool in_ap = FALSE; ++ unsigned long flags; ++#endif ++#ifndef USE_KTHREAD_API ++ DAEMONIZE("dhd_sysioc"); ++ ++ complete(&tsk->completed); ++#endif ++ ++ while (down_interruptible(&tsk->sema) == 0) { ++ ++ SMP_RD_BARRIER_DEPENDS(); ++ if (tsk->terminated) { ++ break; ++ } ++ ++ dhd_net_if_lock_local(dhd); ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ if (dhd->iflist[i]) { ++ AP6211_DEBUG("%s: interface %d\n", __FUNCTION__, i); ++#ifdef SOFTAP ++ flags = dhd_os_spin_lock(&dhd->pub); ++ in_ap = (ap_net_dev != NULL); ++ dhd_os_spin_unlock(&dhd->pub, flags); ++#endif /* SOFTAP */ ++ if (dhd->iflist[i] && dhd->iflist[i]->state) ++ dhd_op_if(dhd->iflist[i]); ++ ++ if (dhd->iflist[i] == NULL) { ++ AP6211_DEBUG("%s: interface %d just been removed,!\n", __FUNCTION__, i); ++ continue; ++ } ++#ifdef SOFTAP ++ if (in_ap && dhd->set_macaddress == i+1) { ++ AP6211_DEBUG("attempt to set MAC for %s in AP Mode," ++ "blocked. \n", dhd->iflist[i]->net->name); ++ dhd->set_macaddress = 0; ++ continue; ++ } ++ ++ if (in_ap && dhd->iflist[i]->set_multicast) { ++ AP6211_DEBUG("attempt to set MULTICAST list for %s" ++ "in AP Mode, blocked. \n", dhd->iflist[i]->net->name); ++ dhd->iflist[i]->set_multicast = FALSE; ++ continue; ++ } ++#endif /* SOFTAP */ ++ if (dhd->pub.up == 0) ++ continue; ++ if (dhd->iflist[i]->set_multicast) { ++ dhd->iflist[i]->set_multicast = FALSE; ++ _dhd_set_multicast_list(dhd, i); ++ } ++ if (dhd->set_macaddress == i+1) { ++ dhd->set_macaddress = 0; ++ if (_dhd_set_mac_address(dhd, i, &dhd->macvalue) == 0) { ++ AP6211_DEBUG( ++ "dhd_sysioc_thread: MACID is overwritten\n"); ++ } else { ++ AP6211_ERR( ++ "dhd_sysioc_thread: _dhd_set_mac_address() failed\n"); ++ } ++ } ++ } ++ } ++ ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ dhd_net_if_unlock_local(dhd); ++ } ++ AP6211_DEBUG("%s: stopped\n", __FUNCTION__); ++ complete_and_exit(&tsk->completed, 0); ++} ++ ++static int ++dhd_set_mac_address(struct net_device *dev, void *addr) ++{ ++ int ret = 0; ++ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ struct sockaddr *sa = (struct sockaddr *)addr; ++ int ifidx; ++ ++ ifidx = dhd_net2idx(dhd, dev); ++ if (ifidx == DHD_BAD_IF) ++ return -1; ++ ++ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); ++ memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN); ++ dhd->set_macaddress = ifidx+1; ++ up(&dhd->thr_sysioc_ctl.sema); ++ ++ return ret; ++} ++ ++static void ++dhd_set_multicast_list(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int ifidx; ++ ++ ifidx = dhd_net2idx(dhd, dev); ++ if (ifidx == DHD_BAD_IF) ++ return; ++ ++ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); ++ dhd->iflist[ifidx]->set_multicast = TRUE; ++ up(&dhd->thr_sysioc_ctl.sema); ++} ++ ++#ifdef PROP_TXSTATUS ++int ++dhd_os_wlfc_block(dhd_pub_t *pub) ++{ ++ dhd_info_t *di = (dhd_info_t *)(pub->info); ++ ASSERT(di != NULL); ++ spin_lock_bh(&di->wlfc_spinlock); ++ return 1; ++} ++ ++int ++dhd_os_wlfc_unblock(dhd_pub_t *pub) ++{ ++ dhd_info_t *di = (dhd_info_t *)(pub->info); ++ ++ ASSERT(di != NULL); ++ spin_unlock_bh(&di->wlfc_spinlock); ++ return 1; ++} ++ ++const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 }; ++uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; ++#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]] ++ ++#endif /* PROP_TXSTATUS */ ++int ++dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) ++{ ++ int ret; ++ dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); ++ struct ether_header *eh = NULL; ++ ++ /* Reject if down */ ++ if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { ++ /* free the packet here since the caller won't */ ++ PKTFREE(dhdp->osh, pktbuf, TRUE); ++ return -ENODEV; ++ } ++ ++ /* Update multicast statistic */ ++ if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) { ++ uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); ++ eh = (struct ether_header *)pktdata; ++ ++ if (ETHER_ISMULTI(eh->ether_dhost)) ++ dhdp->tx_multicast++; ++ if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) ++ atomic_inc(&dhd->pend_8021x_cnt); ++ } else { ++ PKTFREE(dhd->pub.osh, pktbuf, TRUE); ++ return BCME_ERROR; ++ } ++ ++ /* Look into the packet and update the packet priority */ ++#ifndef PKTPRIO_OVERRIDE ++ if (PKTPRIO(pktbuf) == 0) ++#endif ++ pktsetprio(pktbuf, FALSE); ++ ++#ifdef PROP_TXSTATUS ++ if (dhdp->wlfc_state) { ++ /* store the interface ID */ ++ DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx); ++ ++ /* store destination MAC in the tag as well */ ++ DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost); ++ ++ /* decide which FIFO this packet belongs to */ ++ if (ETHER_ISMULTI(eh->ether_dhost)) ++ /* one additional queue index (highest AC + 1) is used for bc/mc queue */ ++ DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT); ++ else ++ DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf))); ++ } else ++#endif /* PROP_TXSTATUS */ ++ /* If the protocol uses a data header, apply it */ ++ dhd_prot_hdrpush(dhdp, ifidx, pktbuf); ++ ++ /* Use bus module to send data frame */ ++#ifdef WLMEDIA_HTSF ++ dhd_htsf_addtxts(dhdp, pktbuf); ++#endif ++#ifdef PROP_TXSTATUS ++ dhd_os_wlfc_block(dhdp); ++ if (dhdp->wlfc_state && ((athost_wl_status_info_t*)dhdp->wlfc_state)->proptxstatus_mode ++ != WLFC_FCMODE_NONE) { ++ ret = dhd_wlfc_enque_sendq(dhdp->wlfc_state, DHD_PKTTAG_FIFO(PKTTAG(pktbuf)), ++ pktbuf); ++ dhd_wlfc_commit_packets(dhdp->wlfc_state, (f_commitpkt_t)dhd_bus_txdata, ++ dhdp->bus); ++ if (((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if) { ++ ((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if = 0; ++ } ++ dhd_os_wlfc_unblock(dhdp); ++ } ++ else { ++ dhd_os_wlfc_unblock(dhdp); ++ /* non-proptxstatus way */ ++ ret = dhd_bus_txdata(dhdp->bus, pktbuf, FALSE); ++ } ++#else ++ ret = dhd_bus_txdata(dhdp->bus, pktbuf, FALSE); ++#endif /* PROP_TXSTATUS */ ++ ++ return ret; ++} ++ ++int ++dhd_start_xmit(struct sk_buff *skb, struct net_device *net) ++{ ++ int ret; ++ void *pktbuf; ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); ++ int ifidx; ++#ifdef WLMEDIA_HTSF ++ uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz; ++#else ++ uint8 htsfdlystat_sz = 0; ++#endif ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ ++ /* Reject if down */ ++ if (dhd->pub.busstate == DHD_BUS_DOWN || dhd->pub.hang_was_sent) { ++ AP6211_ERR("%s: xmit rejected pub.up=%d busstate=%d \n", ++ __FUNCTION__, dhd->pub.up, dhd->pub.busstate); ++ netif_stop_queue(net); ++ /* Send Event when bus down detected during data session */ ++ if (dhd->pub.up) { ++ AP6211_ERR("%s: Event HANG sent up\n", __FUNCTION__); ++ net_os_send_hang_message(net); ++ } ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) ++ return -ENODEV; ++#else ++ return NETDEV_TX_BUSY; ++#endif ++ } ++ ++ ifidx = dhd_net2idx(dhd, net); ++ if (ifidx == DHD_BAD_IF) { ++ AP6211_ERR("%s: bad ifidx %d\n", __FUNCTION__, ifidx); ++ netif_stop_queue(net); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) ++ return -ENODEV; ++#else ++ return NETDEV_TX_BUSY; ++#endif ++ } ++ ++ /* Make sure there's enough room for any header */ ++ ++ if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) { ++ struct sk_buff *skb2; ++ ++ AP6211_DEBUG("%s: insufficient headroom\n", ++ dhd_ifname(&dhd->pub, ifidx)); ++ dhd->pub.tx_realloc++; ++ ++ skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz); ++ ++ dev_kfree_skb(skb); ++ if ((skb = skb2) == NULL) { ++ AP6211_ERR("%s: skb_realloc_headroom failed\n", ++ dhd_ifname(&dhd->pub, ifidx)); ++ ret = -ENOMEM; ++ goto done; ++ } ++ } ++ ++ /* Convert to packet */ ++ if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) { ++ AP6211_ERR("%s: PKTFRMNATIVE failed\n", ++ dhd_ifname(&dhd->pub, ifidx)); ++ dev_kfree_skb_any(skb); ++ ret = -ENOMEM; ++ goto done; ++ } ++#ifdef WLMEDIA_HTSF ++ if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) { ++ uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf); ++ struct ether_header *eh = (struct ether_header *)pktdata; ++ ++ if (!ETHER_ISMULTI(eh->ether_dhost) && ++ (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) { ++ eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS); ++ } ++ } ++#endif ++ ++ ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf); ++ ++ ++done: ++ if (ret) ++ dhd->pub.dstats.tx_dropped++; ++ else ++ dhd->pub.tx_packets++; ++ ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ ++ /* Return ok: we always eat the packet */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) ++ return 0; ++#else ++ return NETDEV_TX_OK; ++#endif ++} ++ ++void ++dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) ++{ ++ struct net_device *net; ++ dhd_info_t *dhd = dhdp->info; ++ int i; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ ASSERT(dhd); ++ ++ if (ifidx == ALL_INTERFACES) { ++ /* Flow control on all active interfaces */ ++ dhdp->txoff = state; ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ if (dhd->iflist[i]) { ++ net = dhd->iflist[i]->net; ++ if (state == ON) ++ netif_stop_queue(net); ++ else ++ netif_wake_queue(net); ++ } ++ } ++ } ++ else { ++ if (dhd->iflist[ifidx]) { ++ net = dhd->iflist[ifidx]->net; ++ if (state == ON) ++ netif_stop_queue(net); ++ else ++ netif_wake_queue(net); ++ } ++ } ++} ++ ++#ifdef DHD_RX_DUMP ++typedef struct { ++ uint16 type; ++ const char *str; ++} PKTTYPE_INFO; ++ ++static const PKTTYPE_INFO packet_type_info[] = ++{ ++ { ETHER_TYPE_IP, "IP" }, ++ { ETHER_TYPE_ARP, "ARP" }, ++ { ETHER_TYPE_BRCM, "BRCM" }, ++ { ETHER_TYPE_802_1X, "802.1X" }, ++ { ETHER_TYPE_WAI, "WAPI" }, ++ { 0, ""} ++}; ++ ++static const char *_get_packet_type_str(uint16 type) ++{ ++ int i; ++ int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1; ++ ++ for (i = 0; i < n; i++) { ++ if (packet_type_info[i].type == type) ++ return packet_type_info[i].str; ++ } ++ ++ return packet_type_info[n].str; ++} ++#endif /* DHD_RX_DUMP */ ++ ++void ++dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ struct sk_buff *skb; ++ uchar *eth; ++ uint len; ++ void *data, *pnext = NULL; ++ int i; ++ dhd_if_t *ifp; ++ wl_event_msg_t event; ++ int tout_rx = 0; ++ int tout_ctrl = 0; ++ ++#ifdef DHD_RX_DUMP ++#ifdef DHD_RX_FULL_DUMP ++ int k; ++#endif /* DHD_RX_FULL_DUMP */ ++ char *dump_data; ++ uint16 protocol; ++#endif /* DHD_RX_DUMP */ ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { ++#ifdef WLBTAMP ++ struct ether_header *eh; ++ struct dot11_llc_snap_header *lsh; ++#endif ++ ++ ifp = dhd->iflist[ifidx]; ++ if (ifp == NULL) { ++ AP6211_ERR("%s: ifp is NULL. drop packet\n", ++ __FUNCTION__); ++ PKTFREE(dhdp->osh, pktbuf, TRUE); ++ continue; ++ } ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++ /* Dropping packets before registering net device to avoid kernel panic */ ++#ifndef PROP_TXSTATUS_VSDB ++ if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) { ++#else ++ if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) { ++#endif /* PROP_TXSTATUS_VSDB */ ++ AP6211_ERR("%s: net device is NOT registered yet. drop packet\n", ++ __FUNCTION__); ++ PKTFREE(dhdp->osh, pktbuf, TRUE); ++ continue; ++ } ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ ++ ++ pnext = PKTNEXT(dhdp->osh, pktbuf); ++ PKTSETNEXT(wl->sh.osh, pktbuf, NULL); ++ ++#ifdef WLBTAMP ++ eh = (struct ether_header *)PKTDATA(wl->sh.osh, pktbuf); ++ lsh = (struct dot11_llc_snap_header *)&eh[1]; ++ ++ if ((ntoh16(eh->ether_type) < ETHER_TYPE_MIN) && ++ (PKTLEN(wl->sh.osh, pktbuf) >= RFC1042_HDR_LEN) && ++ bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && ++ lsh->type == HTON16(BTA_PROT_L2CAP)) { ++ amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *) ++ ((uint8 *)eh + RFC1042_HDR_LEN); ++ ACL_data = NULL; ++ } ++#endif /* WLBTAMP */ ++ ++#ifdef PROP_TXSTATUS ++ if (dhdp->wlfc_state && PKTLEN(wl->sh.osh, pktbuf) == 0) { ++ /* WLFC may send header only packet when ++ there is an urgent message but no packet to ++ piggy-back on ++ */ ++ ((athost_wl_status_info_t*)dhdp->wlfc_state)->stats.wlfc_header_only_pkt++; ++ PKTFREE(dhdp->osh, pktbuf, TRUE); ++ continue; ++ } ++#endif ++ ++ skb = PKTTONATIVE(dhdp->osh, pktbuf); ++ ++ /* Get the protocol, maintain skb around eth_type_trans() ++ * The main reason for this hack is for the limitation of ++ * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len' ++ * to perform skb_pull inside vs ETH_HLEN. Since to avoid ++ * coping of the packet coming from the network stack to add ++ * BDC, Hardware header etc, during network interface registration ++ * we set the 'net->hard_header_len' to ETH_HLEN + extra space required ++ * for BDC, Hardware header etc. and not just the ETH_HLEN ++ */ ++ eth = skb->data; ++ len = skb->len; ++ ++#ifdef DHD_RX_DUMP ++ dump_data = skb->data; ++ protocol = (dump_data[12] << 8) | dump_data[13]; ++ AP6211_ERR("RX DUMP - %s\n", _get_packet_type_str(protocol)); ++ ++#ifdef DHD_RX_FULL_DUMP ++ if (protocol != ETHER_TYPE_BRCM) { ++ for (k = 0; k < skb->len; k++) { ++ AP6211_ERR("%02X ", dump_data[k])); ++ if ((k & 15) == 15) ++ AP6211_ERR("\n"); ++ } ++ AP6211_ERR("\n"); ++ } ++#endif /* DHD_RX_FULL_DUMP */ ++ ++ if (protocol != ETHER_TYPE_BRCM) { ++ if (dump_data[0] == 0xFF) { ++ AP6211_ERR("%s: BROADCAST\n", __FUNCTION__); ++ ++ if ((dump_data[12] == 8) && ++ (dump_data[13] == 6)) { ++ AP6211_ERR("%s: ARP %d\n", ++ __FUNCTION__, dump_data[0x15]); ++ } ++ } else if (dump_data[0] & 1) { ++ AP6211_ERR("%s: MULTICAST: " MACDBG "\n", ++ __FUNCTION__, MAC2STRDBG(dump_data)); ++ } ++ ++ if (protocol == ETHER_TYPE_802_1X) { ++ AP6211_ERR("ETHER_TYPE_802_1X: " ++ "ver %d, type %d, replay %d\n", ++ dump_data[14], dump_data[15], ++ dump_data[30]); ++ } ++ } ++ ++#endif /* DHD_RX_DUMP */ ++ ++ ifp = dhd->iflist[ifidx]; ++ if (ifp == NULL) ++ ifp = dhd->iflist[0]; ++ ++ ASSERT(ifp); ++ skb->dev = ifp->net; ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ ++ if (skb->pkt_type == PACKET_MULTICAST) { ++ dhd->pub.rx_multicast++; ++ } ++ ++ skb->data = eth; ++ skb->len = len; ++ ++#ifdef WLMEDIA_HTSF ++ dhd_htsf_addrxts(dhdp, pktbuf); ++#endif ++ /* Strip header, count, deliver upward */ ++ skb_pull(skb, ETH_HLEN); ++ ++ /* Process special event packets and then discard them */ ++ if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) { ++ dhd_wl_host_event(dhd, &ifidx, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) ++ skb->mac_header, ++#else ++ skb->mac.raw, ++#endif ++ &event, ++ &data); ++ ++ wl_event_to_host_order(&event); ++ if (!tout_ctrl) ++ tout_ctrl = DHD_PACKET_TIMEOUT_MS; ++#ifdef WLBTAMP ++ if (event.event_type == WLC_E_BTA_HCI_EVENT) { ++ dhd_bta_doevt(dhdp, data, event.datalen); ++ } ++#endif /* WLBTAMP */ ++ ++#if defined(PNO_SUPPORT) ++ if (event.event_type == WLC_E_PFN_NET_FOUND) { ++ /* enforce custom wake lock to garantee that Kernel not suspended */ ++ tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS; ++ } ++#endif /* PNO_SUPPORT */ ++ ++#ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT ++ PKTFREE(dhdp->osh, pktbuf, TRUE); ++ continue; ++#endif ++ } else { ++ tout_rx = DHD_PACKET_TIMEOUT_MS; ++ } ++ ++ ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); ++ if (dhd->iflist[ifidx] && !dhd->iflist[ifidx]->state) ++ ifp = dhd->iflist[ifidx]; ++ ++ if (ifp->net) ++ ifp->net->last_rx = jiffies; ++ ++ dhdp->dstats.rx_bytes += skb->len; ++ dhdp->rx_packets++; /* Local count */ ++ ++ if (in_interrupt()) { ++ netif_rx(skb); ++ } else { ++ /* If the receive is not processed inside an ISR, ++ * the softirqd must be woken explicitly to service ++ * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled ++ * by netif_rx_ni(), but in earlier kernels, we need ++ * to do it manually. ++ */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++ netif_rx_ni(skb); ++#else ++ ulong flags; ++ netif_rx(skb); ++ local_irq_save(flags); ++ RAISE_RX_SOFTIRQ(); ++ local_irq_restore(flags); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ ++ } ++ } ++ ++ DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx); ++ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl); ++} ++ ++void ++dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx) ++{ ++ /* Linux version has nothing to do */ ++ return; ++} ++ ++void ++dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); ++ struct ether_header *eh; ++ uint16 type; ++#ifdef WLBTAMP ++ uint len; ++#endif ++ ++ dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL); ++ ++ eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); ++ type = ntoh16(eh->ether_type); ++ ++ if (type == ETHER_TYPE_802_1X) ++ atomic_dec(&dhd->pend_8021x_cnt); ++ ++#ifdef WLBTAMP ++ /* Crack open the packet and check to see if it is BT HCI ACL data packet. ++ * If yes generate packet completion event. ++ */ ++ len = PKTLEN(dhdp->osh, txp); ++ ++ /* Generate ACL data tx completion event locally to avoid SDIO bus transaction */ ++ if ((type < ETHER_TYPE_MIN) && (len >= RFC1042_HDR_LEN)) { ++ struct dot11_llc_snap_header *lsh = (struct dot11_llc_snap_header *)&eh[1]; ++ ++ if (bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && ++ ntoh16(lsh->type) == BTA_PROT_L2CAP) { ++ ++ dhd_bta_tx_hcidata_complete(dhdp, txp, success); ++ } ++ } ++#endif /* WLBTAMP */ ++} ++ ++static struct net_device_stats * ++dhd_get_stats(struct net_device *net) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); ++ dhd_if_t *ifp; ++ int ifidx; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ ifidx = dhd_net2idx(dhd, net); ++ if (ifidx == DHD_BAD_IF) { ++ AP6211_ERR("%s: BAD_IF\n", __FUNCTION__); ++ return NULL; ++ } ++ ++ ifp = dhd->iflist[ifidx]; ++ ASSERT(dhd && ifp); ++ ++ if (dhd->pub.up) { ++ /* Use the protocol to get dongle stats */ ++ dhd_prot_dstats(&dhd->pub); ++ } ++ ++ /* Copy dongle stats to net device stats */ ++ ifp->stats.rx_packets = dhd->pub.dstats.rx_packets; ++ ifp->stats.tx_packets = dhd->pub.dstats.tx_packets; ++ ifp->stats.rx_bytes = dhd->pub.dstats.rx_bytes; ++ ifp->stats.tx_bytes = dhd->pub.dstats.tx_bytes; ++ ifp->stats.rx_errors = dhd->pub.dstats.rx_errors; ++ ifp->stats.tx_errors = dhd->pub.dstats.tx_errors; ++ ifp->stats.rx_dropped = dhd->pub.dstats.rx_dropped; ++ ifp->stats.tx_dropped = dhd->pub.dstats.tx_dropped; ++ ifp->stats.multicast = dhd->pub.dstats.multicast; ++ ++ return &ifp->stats; ++} ++ ++#ifdef DHDTHREAD ++static int ++dhd_watchdog_thread(void *data) ++{ ++ tsk_ctl_t *tsk = (tsk_ctl_t *)data; ++ dhd_info_t *dhd = (dhd_info_t *)tsk->parent; ++ /* This thread doesn't need any user-level access, ++ * so get rid of all our resources ++ */ ++ if (dhd_watchdog_prio > 0) { ++ struct sched_param param; ++ param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)? ++ dhd_watchdog_prio:(MAX_RT_PRIO-1); ++ setScheduler(current, SCHED_FIFO, ¶m); ++ } ++#ifndef USE_KTHREAD_API ++ DAEMONIZE("dhd_watchdog"); ++ ++ /* Run until signal received */ ++ complete(&tsk->completed); ++#endif ++ ++ while (1) ++ if (down_interruptible (&tsk->sema) == 0) { ++ unsigned long flags; ++ unsigned long jiffies_at_start = jiffies; ++ unsigned long time_lapse; ++ ++ SMP_RD_BARRIER_DEPENDS(); ++ if (tsk->terminated) { ++ break; ++ } ++ ++ dhd_os_sdlock(&dhd->pub); ++ if (dhd->pub.dongle_reset == FALSE) { ++ AP6211_DEBUG("%s:\n", __FUNCTION__); ++ ++ /* Call the bus module watchdog */ ++ dhd_bus_watchdog(&dhd->pub); ++ ++ flags = dhd_os_spin_lock(&dhd->pub); ++ /* Count the tick for reference */ ++ dhd->pub.tickcnt++; ++ time_lapse = jiffies - jiffies_at_start; ++ ++ /* Reschedule the watchdog */ ++ if (dhd->wd_timer_valid) ++ mod_timer(&dhd->timer, ++ jiffies + ++ msecs_to_jiffies(dhd_watchdog_ms) - ++ min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse)); ++ dhd_os_spin_unlock(&dhd->pub, flags); ++ } ++ dhd_os_sdunlock(&dhd->pub); ++ } else { ++ break; ++ } ++ ++ complete_and_exit(&tsk->completed, 0); ++} ++#endif /* DHDTHREAD */ ++ ++static void dhd_watchdog(ulong data) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)data; ++ unsigned long flags; ++ ++ if (dhd->pub.dongle_reset) { ++ return; ++ } ++ ++#ifdef DHDTHREAD ++ if (dhd->thr_wdt_ctl.thr_pid >= 0) { ++ up(&dhd->thr_wdt_ctl.sema); ++ return; ++ } ++#endif /* DHDTHREAD */ ++ ++ dhd_os_sdlock(&dhd->pub); ++ /* Call the bus module watchdog */ ++ dhd_bus_watchdog(&dhd->pub); ++ ++ flags = dhd_os_spin_lock(&dhd->pub); ++ /* Count the tick for reference */ ++ dhd->pub.tickcnt++; ++ ++ /* Reschedule the watchdog */ ++ if (dhd->wd_timer_valid) ++ mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); ++ dhd_os_spin_unlock(&dhd->pub, flags); ++ dhd_os_sdunlock(&dhd->pub); ++} ++ ++#ifdef DHDTHREAD ++static int ++dhd_dpc_thread(void *data) ++{ ++ tsk_ctl_t *tsk = (tsk_ctl_t *)data; ++ dhd_info_t *dhd = (dhd_info_t *)tsk->parent; ++ ++ /* This thread doesn't need any user-level access, ++ * so get rid of all our resources ++ */ ++ if (dhd_dpc_prio > 0) ++ { ++ struct sched_param param; ++ param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1); ++ setScheduler(current, SCHED_FIFO, ¶m); ++ } ++#ifndef USE_KTHREAD_API ++ DAEMONIZE("dhd_dpc"); ++ /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */ ++ ++ /* signal: thread has started */ ++ complete(&tsk->completed); ++#endif ++ ++ /* Run until signal received */ ++ while (1) { ++ if (down_interruptible(&tsk->sema) == 0) { ++ ++ SMP_RD_BARRIER_DEPENDS(); ++ if (tsk->terminated) { ++ break; ++ } ++ ++ /* Call bus dpc unless it indicated down (then clean stop) */ ++ if (dhd->pub.busstate != DHD_BUS_DOWN) { ++ if (dhd_bus_dpc(dhd->pub.bus)) { ++ up(&tsk->sema); ++ } ++ else { ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ } ++ } else { ++ if (dhd->pub.up) ++ dhd_bus_stop(dhd->pub.bus, TRUE); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ } ++ } ++ else ++ break; ++ } ++ ++ complete_and_exit(&tsk->completed, 0); ++} ++#endif /* DHDTHREAD */ ++ ++static void ++dhd_dpc(ulong data) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)data; ++ ++ /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c] ++ * down below , wake lock is set, ++ * the tasklet is initialized in dhd_attach() ++ */ ++ /* Call bus dpc unless it indicated down (then clean stop) */ ++ if (dhd->pub.busstate != DHD_BUS_DOWN) { ++ if (dhd_bus_dpc(dhd->pub.bus)) ++ tasklet_schedule(&dhd->tasklet); ++ else ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ } else { ++ dhd_bus_stop(dhd->pub.bus, TRUE); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ } ++} ++ ++void ++dhd_sched_dpc(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ ++ DHD_OS_WAKE_LOCK(dhdp); ++#ifdef DHDTHREAD ++ if (dhd->thr_dpc_ctl.thr_pid >= 0) { ++ up(&dhd->thr_dpc_ctl.sema); ++ return; ++ } ++#endif /* DHDTHREAD */ ++ ++ if (dhd->dhd_tasklet_create) ++ tasklet_schedule(&dhd->tasklet); ++} ++ ++#ifdef TOE ++/* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */ ++static int ++dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol) ++{ ++ wl_ioctl_t ioc; ++ char buf[32]; ++ int ret; ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ++ ioc.cmd = WLC_GET_VAR; ++ ioc.buf = buf; ++ ioc.len = (uint)sizeof(buf); ++ ioc.set = FALSE; ++ ++ strncpy(buf, "toe_ol", sizeof(buf) - 1); ++ buf[sizeof(buf) - 1] = '\0'; ++ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { ++ /* Check for older dongle image that doesn't support toe_ol */ ++ if (ret == -EIO) { ++ AP6211_ERR("%s: toe not supported by device\n", ++ dhd_ifname(&dhd->pub, ifidx)); ++ return -EOPNOTSUPP; ++ } ++ ++ AP6211_DEBUG("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret); ++ return ret; ++ } ++ ++ memcpy(toe_ol, buf, sizeof(uint32)); ++ return 0; ++} ++ ++/* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */ ++static int ++dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol) ++{ ++ wl_ioctl_t ioc; ++ char buf[32]; ++ int toe, ret; ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ++ ioc.cmd = WLC_SET_VAR; ++ ioc.buf = buf; ++ ioc.len = (uint)sizeof(buf); ++ ioc.set = TRUE; ++ ++ /* Set toe_ol as requested */ ++ ++ strncpy(buf, "toe_ol", sizeof(buf) - 1); ++ buf[sizeof(buf) - 1] = '\0'; ++ memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32)); ++ ++ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { ++ AP6211_ERR("%s: could not set toe_ol: ret=%d\n", ++ dhd_ifname(&dhd->pub, ifidx), ret); ++ return ret; ++ } ++ ++ /* Enable toe globally only if any components are enabled. */ ++ ++ toe = (toe_ol != 0); ++ ++ strcpy(buf, "toe"); ++ memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32)); ++ ++ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { ++ AP6211_ERR("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret); ++ return ret; ++ } ++ ++ return 0; ++} ++#endif /* TOE */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) ++static void ++dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); ++ ++ snprintf(info->driver, sizeof(info->driver), "wl"); ++ snprintf(info->version, sizeof(info->version), "%lu", dhd->pub.drv_version); ++} ++ ++struct ethtool_ops dhd_ethtool_ops = { ++ .get_drvinfo = dhd_ethtool_get_drvinfo ++}; ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ ++ ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) ++static int ++dhd_ethtool(dhd_info_t *dhd, void *uaddr) ++{ ++ struct ethtool_drvinfo info; ++ char drvname[sizeof(info.driver)]; ++ uint32 cmd; ++#ifdef TOE ++ struct ethtool_value edata; ++ uint32 toe_cmpnt, csum_dir; ++ int ret; ++#endif ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ /* all ethtool calls start with a cmd word */ ++ if (copy_from_user(&cmd, uaddr, sizeof (uint32))) ++ return -EFAULT; ++ ++ switch (cmd) { ++ case ETHTOOL_GDRVINFO: ++ /* Copy out any request driver name */ ++ if (copy_from_user(&info, uaddr, sizeof(info))) ++ return -EFAULT; ++ strncpy(drvname, info.driver, sizeof(info.driver)); ++ drvname[sizeof(info.driver)-1] = '\0'; ++ ++ /* clear struct for return */ ++ memset(&info, 0, sizeof(info)); ++ info.cmd = cmd; ++ ++ /* if dhd requested, identify ourselves */ ++ if (strcmp(drvname, "?dhd") == 0) { ++ snprintf(info.driver, sizeof(info.driver), "dhd"); ++ strncpy(info.version, EPI_VERSION_STR, sizeof(info.version) - 1); ++ info.version[sizeof(info.version) - 1] = '\0'; ++ } ++ ++ /* otherwise, require dongle to be up */ ++ else if (!dhd->pub.up) { ++ AP6211_ERR("%s: dongle is not up\n", __FUNCTION__); ++ return -ENODEV; ++ } ++ ++ /* finally, report dongle driver type */ ++ else if (dhd->pub.iswl) ++ snprintf(info.driver, sizeof(info.driver), "wl"); ++ else ++ snprintf(info.driver, sizeof(info.driver), "xx"); ++ ++ snprintf(info.version, sizeof(info.version), "%lu", dhd->pub.drv_version); ++ if (copy_to_user(uaddr, &info, sizeof(info))) ++ return -EFAULT; ++ AP6211_DEBUG("%s: given %*s, returning %s\n", __FUNCTION__, ++ (int)sizeof(drvname), drvname, info.driver); ++ break; ++ ++#ifdef TOE ++ /* Get toe offload components from dongle */ ++ case ETHTOOL_GRXCSUM: ++ case ETHTOOL_GTXCSUM: ++ if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0) ++ return ret; ++ ++ csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; ++ ++ edata.cmd = cmd; ++ edata.data = (toe_cmpnt & csum_dir) ? 1 : 0; ++ ++ if (copy_to_user(uaddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ break; ++ ++ /* Set toe offload components in dongle */ ++ case ETHTOOL_SRXCSUM: ++ case ETHTOOL_STXCSUM: ++ if (copy_from_user(&edata, uaddr, sizeof(edata))) ++ return -EFAULT; ++ ++ /* Read the current settings, update and write back */ ++ if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0) ++ return ret; ++ ++ csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; ++ ++ if (edata.data != 0) ++ toe_cmpnt |= csum_dir; ++ else ++ toe_cmpnt &= ~csum_dir; ++ ++ if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0) ++ return ret; ++ ++ /* If setting TX checksum mode, tell Linux the new mode */ ++ if (cmd == ETHTOOL_STXCSUM) { ++ if (edata.data) ++ dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM; ++ else ++ dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM; ++ } ++ ++ break; ++#endif /* TOE */ ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ ++ ++static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) ++{ ++ dhd_info_t * dhd; ++ ++ if (!dhdp) ++ return FALSE; ++ ++ dhd = (dhd_info_t *)dhdp->info; ++ if (dhd->thr_sysioc_ctl.thr_pid < 0) { ++ AP6211_ERR("%s : skipped due to negative pid - unloading?\n", __FUNCTION__); ++ return FALSE; ++ } ++ ++ if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) || ++ ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) { ++ AP6211_ERR("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, ++ dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate); ++ net_os_send_hang_message(net); ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++static int ++dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); ++ dhd_ioctl_t ioc; ++ int bcmerror = 0; ++ int buflen = 0; ++ void *buf = NULL; ++ uint driver = 0; ++ int ifidx; ++ int ret; ++ ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ ++ /* send to dongle only if we are not waiting for reload already */ ++ if (dhd->pub.hang_was_sent) { ++ AP6211_ERR("%s: HANG was sent up earlier\n", __FUNCTION__); ++ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return OSL_ERROR(BCME_DONGLE_DOWN); ++ } ++ ++ ifidx = dhd_net2idx(dhd, net); ++ AP6211_DEBUG("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd); ++ ++ if (ifidx == DHD_BAD_IF) { ++ AP6211_ERR("%s: BAD IF\n", __FUNCTION__); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return -1; ++ } ++ ++#if defined(CONFIG_WIRELESS_EXT) ++ /* linux wireless extensions */ ++ if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { ++ /* may recurse, do NOT lock */ ++ ret = wl_iw_ioctl(net, ifr, cmd); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return ret; ++ } ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) ++ if (cmd == SIOCETHTOOL) { ++ ret = dhd_ethtool(dhd, (void*)ifr->ifr_data); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return ret; ++ } ++#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ ++ ++ if (cmd == SIOCDEVPRIVATE+1) { ++ ret = wl_android_priv_cmd(net, ifr, cmd); ++ dhd_check_hang(net, &dhd->pub, ret); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return ret; ++ } ++ ++ if (cmd != SIOCDEVPRIVATE) { ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return -EOPNOTSUPP; ++ } ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ++ /* Copy the ioc control structure part of ioctl request */ ++ if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { ++ bcmerror = BCME_BADADDR; ++ goto done; ++ } ++ ++ /* Copy out any buffer passed */ ++ if (ioc.buf) { ++ if (ioc.len == 0) { ++ AP6211_DEBUG("%s: ioc.len=0, returns BCME_BADARG \n", __FUNCTION__); ++ bcmerror = BCME_BADARG; ++ goto done; ++ } ++ buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN); ++ /* optimization for direct ioctl calls from kernel */ ++ /* ++ if (segment_eq(get_fs(), KERNEL_DS)) { ++ buf = ioc.buf; ++ } else { ++ */ ++ { ++ if (!(buf = (char*)MALLOC(dhd->pub.osh, buflen))) { ++ bcmerror = BCME_NOMEM; ++ goto done; ++ } ++ if (copy_from_user(buf, ioc.buf, buflen)) { ++ bcmerror = BCME_BADADDR; ++ goto done; ++ } ++ } ++ } ++ ++ /* To differentiate between wl and dhd read 4 more byes */ ++ if ((copy_from_user(&driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), ++ sizeof(uint)) != 0)) { ++ bcmerror = BCME_BADADDR; ++ goto done; ++ } ++ ++ if (!capable(CAP_NET_ADMIN)) { ++ bcmerror = BCME_EPERM; ++ goto done; ++ } ++ ++ /* check for local dhd ioctl and handle it */ ++ if (driver == DHD_IOCTL_MAGIC) { ++ bcmerror = dhd_ioctl((void *)&dhd->pub, &ioc, buf, buflen); ++ if (bcmerror) ++ dhd->pub.bcmerror = bcmerror; ++ goto done; ++ } ++ ++ /* send to dongle (must be up, and wl). */ ++ if (dhd->pub.busstate != DHD_BUS_DATA) { ++ bcmerror = BCME_DONGLE_DOWN; ++ goto done; ++ } ++ ++ if (!dhd->pub.iswl) { ++ bcmerror = BCME_DONGLE_DOWN; ++ goto done; ++ } ++ ++ /* ++ * Flush the TX queue if required for proper message serialization: ++ * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to ++ * prevent M4 encryption and ++ * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to ++ * prevent disassoc frame being sent before WPS-DONE frame. ++ */ ++ if (ioc.cmd == WLC_SET_KEY || ++ (ioc.cmd == WLC_SET_VAR && ioc.buf != NULL && ++ strncmp("wsec_key", ioc.buf, 9) == 0) || ++ (ioc.cmd == WLC_SET_VAR && ioc.buf != NULL && ++ strncmp("bsscfg:wsec_key", ioc.buf, 15) == 0) || ++ ioc.cmd == WLC_DISASSOC) ++ dhd_wait_pend8021x(net); ++ ++#ifdef WLMEDIA_HTSF ++ if (ioc.buf) { ++ /* short cut wl ioctl calls here */ ++ if (strcmp("htsf", ioc.buf) == 0) { ++ dhd_ioctl_htsf_get(dhd, 0); ++ return BCME_OK; ++ } ++ ++ if (strcmp("htsflate", ioc.buf) == 0) { ++ if (ioc.set) { ++ memset(ts, 0, sizeof(tstamp_t)*TSMAX); ++ memset(&maxdelayts, 0, sizeof(tstamp_t)); ++ maxdelay = 0; ++ tspktcnt = 0; ++ maxdelaypktno = 0; ++ memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); ++ } else { ++ dhd_dump_latency(); ++ } ++ return BCME_OK; ++ } ++ if (strcmp("htsfclear", ioc.buf) == 0) { ++ memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); ++ htsf_seqnum = 0; ++ return BCME_OK; ++ } ++ if (strcmp("htsfhis", ioc.buf) == 0) { ++ dhd_dump_htsfhisto(&vi_d1, "H to D"); ++ dhd_dump_htsfhisto(&vi_d2, "D to D"); ++ dhd_dump_htsfhisto(&vi_d3, "D to H"); ++ dhd_dump_htsfhisto(&vi_d4, "H to H"); ++ return BCME_OK; ++ } ++ if (strcmp("tsport", ioc.buf) == 0) { ++ if (ioc.set) { ++ memcpy(&tsport, ioc.buf + 7, 4); ++ } else { ++ AP6211_ERR("current timestamp port: %d \n", tsport); ++ } ++ return BCME_OK; ++ } ++ } ++#endif /* WLMEDIA_HTSF */ ++ ++ if ((ioc.cmd == WLC_SET_VAR || ioc.cmd == WLC_GET_VAR) && ++ ioc.buf != NULL && strncmp("rpc_", ioc.buf, 4) == 0) { ++#ifdef BCM_FD_AGGR ++ bcmerror = dhd_fdaggr_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); ++#else ++ bcmerror = BCME_UNSUPPORTED; ++#endif ++ goto done; ++ } ++ bcmerror = dhd_wl_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); ++ ++done: ++ dhd_check_hang(net, &dhd->pub, bcmerror); ++ ++ if (!bcmerror && buf && ioc.buf) { ++ if (copy_to_user(ioc.buf, buf, buflen)) ++ bcmerror = -EFAULT; ++ } ++ ++ if (buf) ++ MFREE(dhd->pub.osh, buf, buflen); ++ ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ ++ return OSL_ERROR(bcmerror); ++} ++ ++#ifdef WL_CFG80211 ++static int ++dhd_cleanup_virt_ifaces(dhd_info_t *dhd) ++{ ++ int i = 1; /* Leave ifidx 0 [Primary Interface] */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ int rollback_lock = FALSE; ++#endif ++ ++ AP6211_DEBUG("%s: Enter \n", __func__); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ /* release lock for unregister_netdev */ ++ if (rtnl_is_locked()) { ++ rtnl_unlock(); ++ rollback_lock = TRUE; ++ } ++#endif ++ ++ for (i = 1; i < DHD_MAX_IFS; i++) { ++ dhd_net_if_lock_local(dhd); ++ if (dhd->iflist[i]) { ++ AP6211_DEBUG("Deleting IF: %d \n", i); ++ if ((dhd->iflist[i]->state != DHD_IF_DEL) && ++ (dhd->iflist[i]->state != DHD_IF_DELETING)) { ++ dhd->iflist[i]->state = DHD_IF_DEL; ++ dhd->iflist[i]->idx = i; ++ dhd_op_if(dhd->iflist[i]); ++ } ++ } ++ dhd_net_if_unlock_local(dhd); ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ if (rollback_lock) ++ rtnl_lock(); ++#endif ++ ++ return 0; ++} ++#endif /* WL_CFG80211 */ ++ ++ ++static int ++dhd_stop(struct net_device *net) ++{ ++ int ifidx = 0; ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ AP6211_DEBUG("%s: Enter %p\n", __FUNCTION__, net); ++ if (dhd->pub.up == 0) { ++ goto exit; ++ } ++ ifidx = dhd_net2idx(dhd, net); ++ BCM_REFERENCE(ifidx); ++ ++ /* Set state and stop OS transmissions */ ++ netif_stop_queue(net); ++ dhd->pub.up = 0; ++ ++#ifdef WL_CFG80211 ++ if (ifidx == 0) { ++ wl_cfg80211_down(NULL); ++ ++ /* ++ * For CFG80211: Clean up all the left over virtual interfaces ++ * when the primary Interface is brought down. [ifconfig wlan0 down] ++ */ ++ if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) && ++ (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { ++ dhd_cleanup_virt_ifaces(dhd); ++ } ++ } ++#endif ++ ++#ifdef PROP_TXSTATUS ++ dhd_os_wlfc_block(&dhd->pub); ++ dhd_wlfc_cleanup(&dhd->pub); ++ dhd_os_wlfc_unblock(&dhd->pub); ++#endif ++ /* Stop the protocol module */ ++ dhd_prot_stop(&dhd->pub); ++ ++ OLD_MOD_DEC_USE_COUNT; ++exit: ++#if defined(WL_CFG80211) ++ if (ifidx == 0) { ++ if (!dhd_download_fw_on_driverload) ++ wl_android_wifi_off(net); ++ } ++#endif ++ dhd->pub.rxcnt_timeout = 0; ++ dhd->pub.txcnt_timeout = 0; ++ ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return 0; ++} ++ ++static int ++dhd_open(struct net_device *net) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); ++#ifdef TOE ++ uint32 toe_ol; ++#endif ++ int ifidx; ++ int32 ret = 0; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) { ++ AP6211_ERR("%s : dhd_open: call dev open before insmod complete!\n", __FUNCTION__); ++ } ++ mutex_lock(&_dhd_sdio_mutex_lock_); ++#endif ++ ++ AP6211_DEBUG("%s, firmware path %s\n", __func__, firmware_path); ++ ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ /* Update FW path if it was changed */ ++ if (strlen(firmware_path) != 0) { ++ if (firmware_path[strlen(firmware_path)-1] == '\n') ++ firmware_path[strlen(firmware_path)-1] = '\0'; ++ COPY_FW_PATH_BY_CHIP( dhd->pub.bus, fw_path, firmware_path); ++ } ++ ++ ++ dhd->pub.dongle_trap_occured = 0; ++ dhd->pub.hang_was_sent = 0; ++#if !defined(WL_CFG80211) ++ /* ++ * Force start if ifconfig_up gets called before START command ++ * We keep WEXT's wl_control_wl_start to provide backward compatibility ++ * This should be removed in the future ++ */ ++ ret = wl_control_wl_start(net); ++ if (ret != 0) { ++ AP6211_ERR("%s: failed with code %d\n", __FUNCTION__, ret); ++ ret = -1; ++ goto exit; ++ } ++#endif ++ ++ ifidx = dhd_net2idx(dhd, net); ++ AP6211_DEBUG("%s: ifidx %d\n", __FUNCTION__, ifidx); ++ ++ if (ifidx < 0) { ++ AP6211_ERR("%s: Error: called with invalid IF\n", __FUNCTION__); ++ ret = -1; ++ goto exit; ++ } ++ ++ if (!dhd->iflist[ifidx] || dhd->iflist[ifidx]->state == DHD_IF_DEL) { ++ AP6211_ERR("%s: Error: called when IF already deleted\n", __FUNCTION__); ++ ret = -1; ++ goto exit; ++ } ++ ++ if (ifidx == 0) { ++ atomic_set(&dhd->pend_8021x_cnt, 0); ++#if defined(WL_CFG80211) ++ AP6211_ERR("%s\n", dhd_version); ++#if defined(DHD_DEBUG) ++ AP6211_ERR("%s\n", dhd_version_info); ++#endif ++ ++ if (!dhd_download_fw_on_driverload) { ++ ret = wl_android_wifi_on(net); ++ if (ret != 0) { ++ AP6211_ERR("%s: failed with code %d\n", __FUNCTION__, ret); ++ ret = -1; ++ goto exit; ++ } ++ } else { ++ } ++#endif ++ ++ if (dhd->pub.busstate != DHD_BUS_DATA) { ++ ++ /* try to bring up bus */ ++ if ((ret = dhd_bus_start(&dhd->pub)) != 0) { ++ AP6211_ERR("%s: failed with code %d\n", __FUNCTION__, ret); ++ ret = -1; ++ goto exit; ++ } ++ ++ } ++ ++ /* dhd_prot_init has been called in dhd_bus_start or wl_android_wifi_on */ ++ memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); ++ ++#ifdef TOE ++ /* Get current TOE mode from dongle */ ++ if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0) ++ dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM; ++ else ++ dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM; ++#endif /* TOE */ ++ ++#if defined(WL_CFG80211) ++ if (unlikely(wl_cfg80211_up(NULL))) { ++ AP6211_ERR("%s: failed to bring up cfg80211\n", __FUNCTION__); ++ ret = -1; ++ goto exit; ++ } ++#endif /* WL_CFG80211 */ ++ } ++ ++ /* Allow transmit calls */ ++ netif_start_queue(net); ++ dhd->pub.up = 1; ++ ++#ifdef BCMDBGFS ++ dhd_dbg_init(&dhd->pub); ++#endif ++ ++ OLD_MOD_INC_USE_COUNT; ++exit: ++ if (ret) ++ dhd_stop(net); ++ ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ mutex_unlock(&_dhd_sdio_mutex_lock_); ++#endif ++ return ret; ++} ++ ++int dhd_do_driver_init(struct net_device *net) ++{ ++ dhd_info_t *dhd = NULL; ++ ++ if (!net) { ++ AP6211_ERR("Primary Interface not initialized \n"); ++ return -EINVAL; ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++#ifdef MULTIPLE_SUPPLICANT ++ if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) { ++ AP6211_ERR("%s : dhdsdio_probe is already running!\n", __FUNCTION__); ++ return 0; ++ } ++#endif /* MULTIPLE_SUPPLICANT */ ++#endif ++ ++ dhd = *(dhd_info_t **)netdev_priv(net); ++ ++ /* If driver is already initialized, do nothing ++ */ ++ if (dhd->pub.busstate == DHD_BUS_DATA) { ++ AP6211_DEBUG("Driver already Inititalized. Nothing to do"); ++ return 0; ++ } ++ ++ if (dhd_open(net) < 0) { ++ AP6211_ERR("Driver Init Failed \n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++osl_t * ++dhd_osl_attach(void *pdev, uint bustype) ++{ ++ return osl_attach(pdev, bustype, TRUE); ++} ++ ++void ++dhd_osl_detach(osl_t *osh) ++{ ++ if (MALLOCED(osh)) { ++ AP6211_ERR("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh)); ++ } ++ osl_detach(osh); ++#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ dhd_registration_check = FALSE; ++ up(&dhd_registration_sem); ++#if defined(BCMLXSDMMC) ++ up(&dhd_chipup_sem); ++#endif ++#endif ++} ++ ++int ++dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, ++ uint8 *mac_addr, uint32 flags, uint8 bssidx) ++{ ++ dhd_if_t *ifp; ++ ++ AP6211_DEBUG("%s: idx %d, handle->%p\n", __FUNCTION__, ifidx, handle); ++ ++ ASSERT(dhd && (ifidx < DHD_MAX_IFS)); ++ ++ ifp = dhd->iflist[ifidx]; ++ if (ifp != NULL) { ++ if (ifp->net != NULL) { ++ netif_stop_queue(ifp->net); ++ unregister_netdev(ifp->net); ++ free_netdev(ifp->net); ++ } ++ } else ++ if ((ifp = MALLOC(dhd->pub.osh, sizeof(dhd_if_t))) == NULL) { ++ AP6211_ERR("%s: OOM - dhd_if_t\n", __FUNCTION__); ++ return -ENOMEM; ++ } ++ ++ memset(ifp, 0, sizeof(dhd_if_t)); ++ ifp->event2cfg80211 = FALSE; ++ ifp->info = dhd; ++ dhd->iflist[ifidx] = ifp; ++ strncpy(ifp->name, name, IFNAMSIZ); ++ ifp->name[IFNAMSIZ] = '\0'; ++ if (mac_addr != NULL) ++ memcpy(&ifp->mac_addr, mac_addr, ETHER_ADDR_LEN); ++ ++ if (handle == NULL) { ++ ifp->state = DHD_IF_ADD; ++ ifp->idx = ifidx; ++ ifp->bssidx = bssidx; ++ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); ++ up(&dhd->thr_sysioc_ctl.sema); ++ } else ++ ifp->net = (struct net_device *)handle; ++ ++ if (ifidx == 0) { ++ ifp->event2cfg80211 = TRUE; ++ } ++ ++ return 0; ++} ++ ++void ++dhd_del_if(dhd_info_t *dhd, int ifidx) ++{ ++ dhd_if_t *ifp; ++ ++ AP6211_DEBUG("%s: idx %d\n", __FUNCTION__, ifidx); ++ ++ ASSERT(dhd && ifidx && (ifidx < DHD_MAX_IFS)); ++ ifp = dhd->iflist[ifidx]; ++ if (!ifp) { ++ AP6211_ERR("%s: Null interface\n", __FUNCTION__); ++ return; ++ } ++ ++ ifp->state = DHD_IF_DEL; ++ ifp->idx = ifidx; ++ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); ++ up(&dhd->thr_sysioc_ctl.sema); ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) ++static struct net_device_ops dhd_ops_pri = { ++ .ndo_open = dhd_open, ++ .ndo_stop = dhd_stop, ++ .ndo_get_stats = dhd_get_stats, ++ .ndo_do_ioctl = dhd_ioctl_entry, ++ .ndo_start_xmit = dhd_start_xmit, ++ .ndo_set_mac_address = dhd_set_mac_address, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) ++ .ndo_set_rx_mode = dhd_set_multicast_list, ++#else ++ .ndo_set_multicast_list = dhd_set_multicast_list, ++#endif ++}; ++ ++static struct net_device_ops dhd_ops_virt = { ++ .ndo_get_stats = dhd_get_stats, ++ .ndo_do_ioctl = dhd_ioctl_entry, ++ .ndo_start_xmit = dhd_start_xmit, ++ .ndo_set_mac_address = dhd_set_mac_address, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) ++ .ndo_set_rx_mode = dhd_set_multicast_list, ++#else ++ .ndo_set_multicast_list = dhd_set_multicast_list, ++#endif ++}; ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ ++ ++dhd_pub_t * ++dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) ++{ ++ dhd_info_t *dhd = NULL; ++ struct net_device *net = NULL; ++ ++ dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT; ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ AP6211_DEBUG("%s, firmware path %s\n", __func__, firmware_path); ++ ++ /* updates firmware nvram path if it was provided as module parameters */ ++ if ((firmware_path != NULL) && (firmware_path[0] != '\0')) ++ COPY_FW_PATH_BY_CHIP(bus, fw_path, firmware_path); ++ if (strlen(nvram_path) != 0) { ++ strncpy(nv_path, nvram_path, sizeof(nv_path) -1); ++ nv_path[sizeof(nv_path) -1] = '\0'; ++ } ++ ++ /* Allocate etherdev, including space for private structure */ ++ if (!(net = alloc_etherdev(sizeof(dhd)))) { ++ AP6211_ERR("%s: OOM - alloc_etherdev\n", __FUNCTION__); ++ goto fail; ++ } ++ dhd_state |= DHD_ATTACH_STATE_NET_ALLOC; ++ ++ /* Allocate primary dhd_info */ ++ if (!(dhd = MALLOC(osh, sizeof(dhd_info_t)))) { ++ AP6211_ERR("%s: OOM - alloc dhd_info\n", __FUNCTION__); ++ goto fail; ++ } ++ memset(dhd, 0, sizeof(dhd_info_t)); ++ ++#ifdef DHDTHREAD ++ dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID; ++ dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID; ++#endif /* DHDTHREAD */ ++ dhd->dhd_tasklet_create = FALSE; ++ dhd->thr_sysioc_ctl.thr_pid = DHD_PID_KT_INVALID; ++ dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC; ++ ++ /* ++ * Save the dhd_info into the priv ++ */ ++ memcpy((void *)netdev_priv(net), &dhd, sizeof(dhd)); ++ dhd->pub.osh = osh; ++ ++ /* Link to info module */ ++ dhd->pub.info = dhd; ++ /* Link to bus module */ ++ dhd->pub.bus = bus; ++ dhd->pub.hdrlen = bus_hdrlen; ++ ++ /* Set network interface name if it was provided as module parameter */ ++ if (iface_name[0]) { ++ int len; ++ char ch; ++ strncpy(net->name, iface_name, IFNAMSIZ); ++ net->name[IFNAMSIZ - 1] = 0; ++ len = strlen(net->name); ++ ch = net->name[len - 1]; ++ if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2)) ++ strcat(net->name, "%d"); ++ } ++ ++ if (dhd_add_if(dhd, 0, (void *)net, net->name, NULL, 0, 0) == DHD_BAD_IF) ++ goto fail; ++ dhd_state |= DHD_ATTACH_STATE_ADD_IF; ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ++ net->open = NULL; ++#else ++ net->netdev_ops = NULL; ++#endif ++ ++ sema_init(&dhd->proto_sem, 1); ++ ++#ifdef PROP_TXSTATUS ++ spin_lock_init(&dhd->wlfc_spinlock); ++#ifdef PROP_TXSTATUS_VSDB ++ dhd->pub.wlfc_enabled = FALSE; ++#else ++ dhd->pub.wlfc_enabled = TRUE; ++#endif /* PROP_TXSTATUS_VSDB */ ++#endif /* PROP_TXSTATUS */ ++ ++ /* Initialize other structure content */ ++ init_waitqueue_head(&dhd->ioctl_resp_wait); ++ init_waitqueue_head(&dhd->ctrl_wait); ++ ++ /* Initialize the spinlocks */ ++ spin_lock_init(&dhd->sdlock); ++ spin_lock_init(&dhd->txqlock); ++ spin_lock_init(&dhd->dhd_lock); ++ ++ /* Initialize Wakelock stuff */ ++ spin_lock_init(&dhd->wakelock_spinlock); ++ dhd->wakelock_counter = 0; ++ dhd->wakelock_wd_counter = 0; ++ dhd->wakelock_rx_timeout_enable = 0; ++ dhd->wakelock_ctrl_timeout_enable = 0; ++#ifdef CONFIG_HAS_WAKELOCK ++ dhd->wl_wifi = MALLOC(osh, sizeof(struct wake_lock)); ++ dhd->wl_rxwake = MALLOC(osh, sizeof(struct wake_lock)); ++ dhd->wl_ctrlwake = MALLOC(osh, sizeof(struct wake_lock)); ++ dhd->wl_wdwake = MALLOC(osh, sizeof(struct wake_lock)); ++ if (!dhd->wl_wifi || !dhd->wl_rxwake || !dhd->wl_ctrlwake || !dhd->wl_wdwake) { ++ AP6211_ERR("%s: mem alloc for wake lock failed\n", __FUNCTION__); ++ goto fail; ++ } ++ wake_lock_init(dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); ++ wake_lock_init(dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); ++ wake_lock_init(dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake"); ++ wake_lock_init(dhd->wl_wdwake, WAKE_LOCK_SUSPEND, "wlan_wd_wake"); ++#endif /* CONFIG_HAS_WAKELOCK */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ mutex_init(&dhd->dhd_net_if_mutex); ++ mutex_init(&dhd->dhd_suspend_mutex); ++#endif ++ dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; ++ ++ /* Attach and link in the protocol */ ++ if (dhd_prot_attach(&dhd->pub) != 0) { ++ AP6211_ERR("dhd_prot_attach failed\n"); ++ goto fail; ++ } ++ dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH; ++ ++#ifdef WL_CFG80211 ++ /* Attach and link in the cfg80211 */ ++ if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) { ++ AP6211_ERR("wl_cfg80211_attach failed\n"); ++ goto fail; ++ } ++ ++ dhd_monitor_init(&dhd->pub); ++ dhd_state |= DHD_ATTACH_STATE_CFG80211; ++#endif ++#if defined(CONFIG_WIRELESS_EXT) ++ /* Attach and link in the iw */ ++ if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) { ++ if (wl_iw_attach(net, (void *)&dhd->pub) != 0) { ++ AP6211_ERR("wl_iw_attach failed\n"); ++ goto fail; ++ } ++ dhd_state |= DHD_ATTACH_STATE_WL_ATTACH; ++ } ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++ ++ /* Set up the watchdog timer */ ++ init_timer(&dhd->timer); ++ dhd->timer.data = (ulong)dhd; ++ dhd->timer.function = dhd_watchdog; ++ ++#ifdef DHDTHREAD ++ /* Initialize thread based operation and lock */ ++ sema_init(&dhd->sdsem, 1); ++ if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0)) { ++ dhd->threads_only = TRUE; ++ } ++ else { ++ dhd->threads_only = FALSE; ++ } ++ ++ if (dhd_watchdog_prio >= 0) { ++ /* Initialize watchdog thread */ ++#ifdef USE_KTHREAD_API ++ PROC_START2(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread"); ++#else ++ PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0); ++#endif ++ } else { ++ dhd->thr_wdt_ctl.thr_pid = -1; ++ } ++ ++ /* Set up the bottom half handler */ ++ if (dhd_dpc_prio >= 0) { ++ /* Initialize DPC thread */ ++#ifdef USE_KTHREAD_API ++ PROC_START2(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc"); ++#else ++ PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0); ++#endif ++ } else { ++ /* use tasklet for dpc */ ++ tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); ++ dhd->thr_dpc_ctl.thr_pid = -1; ++ } ++#else ++ /* Set up the bottom half handler */ ++ tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); ++ dhd->dhd_tasklet_create = TRUE; ++#endif /* DHDTHREAD */ ++ ++ if (dhd_sysioc) { ++#ifdef USE_KTHREAD_API ++ PROC_START2(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0, "dhd_sysioc"); ++#else ++ PROC_START(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0); ++#endif ++ } else { ++ dhd->thr_sysioc_ctl.thr_pid = -1; ++ } ++ dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1) ++ INIT_WORK(&dhd->work_hang, dhd_hang_process); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++ /* ++ * Save the dhd_info into the priv ++ */ ++ memcpy(netdev_priv(net), &dhd, sizeof(dhd)); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) ++ register_pm_notifier(&dhd_sleep_pm_notifier); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++ dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20; ++ dhd->early_suspend.suspend = dhd_early_suspend; ++ dhd->early_suspend.resume = dhd_late_resume; ++ register_early_suspend(&dhd->early_suspend); ++ dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE; ++#endif ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ dhd->pend_ipaddr = 0; ++ register_inetaddr_notifier(&dhd_notifier); ++#endif /* ARP_OFFLOAD_SUPPORT */ ++#ifdef IPV6 ++ register_inet6addr_notifier(&dhd_notifier_ipv6); ++#endif ++ ++#ifdef DHDTCPACK_SUPPRESS ++ dhd->pub.tcp_ack_info_cnt = 0; ++ bzero(dhd->pub.tcp_ack_info_tbl, sizeof(struct tcp_ack_info)*MAXTCPSTREAMS); ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++ dhd_state |= DHD_ATTACH_STATE_DONE; ++ dhd->dhd_state = dhd_state; ++ return &dhd->pub; ++ ++fail: ++ if (dhd_state < DHD_ATTACH_STATE_DHD_ALLOC) { ++ if (net) free_netdev(net); ++ } else { ++ AP6211_DEBUG("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n", ++ __FUNCTION__, dhd_state, &dhd->pub); ++ dhd->dhd_state = dhd_state; ++ dhd_detach(&dhd->pub); ++ dhd_free(&dhd->pub); ++ } ++ ++ return NULL; ++} ++ ++int ++dhd_bus_start(dhd_pub_t *dhdp) ++{ ++ int ret = -1; ++ dhd_info_t *dhd = (dhd_info_t*)dhdp->info; ++ unsigned long flags; ++ ++ ASSERT(dhd); ++ ++ AP6211_DEBUG("Enter %s:\n", __FUNCTION__); ++ ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ dhd_os_sdlock(dhdp); ++#endif /* DHDTHREAD */ ++ ++ ++ /* try to download image and nvram to the dongle */ ++ if ((dhd->pub.busstate == DHD_BUS_DOWN) && ++ (fw_path != NULL) && (fw_path[0] != '\0') && ++ (nv_path != NULL) && (nv_path[0] != '\0')) { ++ /* wake lock moved to dhdsdio_download_firmware */ ++ if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, ++ fw_path, nv_path))) { ++ AP6211_ERR("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n", ++ __FUNCTION__, fw_path, nv_path); ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ dhd_os_sdunlock(dhdp); ++#endif /* DHDTHREAD */ ++ return -1; ++ } ++ } ++ if (dhd->pub.busstate != DHD_BUS_LOAD) { ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ dhd_os_sdunlock(dhdp); ++#endif /* DHDTHREAD */ ++ return -ENETDOWN; ++ } ++ ++ /* Start the watchdog timer */ ++ dhd->pub.tickcnt = 0; ++ dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); ++ ++ /* Bring up the bus */ ++ if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) { ++ ++ AP6211_ERR("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret); ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ dhd_os_sdunlock(dhdp); ++#endif /* DHDTHREAD */ ++ return ret; ++ } ++ bcmsdh_set_drvdata(dhdp); ++#if defined(OOB_INTR_ONLY) ++ /* Host registration for OOB interrupt */ ++ if (bcmsdh_register_oob_intr(dhdp)) { ++ /* deactivate timer and wait for the handler to finish */ ++ ++ flags = dhd_os_spin_lock(&dhd->pub); ++ dhd->wd_timer_valid = FALSE; ++ dhd_os_spin_unlock(&dhd->pub, flags); ++ del_timer_sync(&dhd->timer); ++ AP6211_ERR("%s Host failed to register for OOB\n", __FUNCTION__); ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ dhd_os_sdunlock(dhdp); ++#endif /* DHDTHREAD */ ++ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); ++ return -ENODEV; ++ } ++ ++ /* Enable oob at firmware */ ++ dhd_enable_oob_intr(dhd->pub.bus, TRUE); ++#endif ++ ++ /* If bus is not ready, can't come up */ ++ if (dhd->pub.busstate != DHD_BUS_DATA) { ++ flags = dhd_os_spin_lock(&dhd->pub); ++ dhd->wd_timer_valid = FALSE; ++ dhd_os_spin_unlock(&dhd->pub, flags); ++ del_timer_sync(&dhd->timer); ++ AP6211_ERR("%s failed bus is not ready\n", __FUNCTION__); ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ dhd_os_sdunlock(dhdp); ++#endif /* DHDTHREAD */ ++ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); ++ return -ENODEV; ++ } ++ ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ dhd_os_sdunlock(dhdp); ++#endif /* DHDTHREAD */ ++ ++#ifdef BCMSDIOH_TXGLOM ++ if ((dhd->pub.busstate == DHD_BUS_DATA) && bcmsdh_glom_enabled()) { ++ dhd_txglom_enable(dhdp, TRUE); ++ } ++#endif ++ ++#ifdef READ_MACADDR ++ dhd_read_macaddr(dhd); ++#endif ++ ++ /* Bus is ready, do any protocol initialization */ ++ if ((ret = dhd_prot_init(&dhd->pub)) < 0) ++ return ret; ++ ++#ifdef WRITE_MACADDR ++ dhd_write_macaddr(dhd->pub.mac.octet); ++#endif ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ if (dhd->pend_ipaddr) { ++#ifdef AOE_IP_ALIAS_SUPPORT ++ aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0); ++#endif /* AOE_IP_ALIAS_SUPPORT */ ++ dhd->pend_ipaddr = 0; ++ } ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++ return 0; ++} ++ ++bool dhd_is_concurrent_mode(dhd_pub_t *dhd) ++{ ++ if (!dhd) ++ return FALSE; ++ ++ if (dhd->op_mode & DHD_FLAG_CONCURR_MULTI_CHAN_MODE) ++ return TRUE; ++ else if ((dhd->op_mode & DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) == ++ DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++#if !defined(AP) && defined(WLP2P) ++/* From Android JerryBean release, the concurrent mode is enabled by default and the firmware ++ * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA ++ * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware ++ * would still be named as fw_bcmdhd_apsta. ++ */ ++uint32 ++dhd_get_concurrent_capabilites(dhd_pub_t *dhd) ++{ ++ int32 ret = 0; ++ char buf[WLC_IOCTL_SMLEN]; ++ bool mchan_supported = FALSE; ++ /* if dhd->op_mode is already set for HOSTAP, ++ * that means we only will use the mode as it is ++ */ ++ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) ++ return 0; ++ memset(buf, 0, sizeof(buf)); ++ bcm_mkiovar("cap", 0, 0, buf, sizeof(buf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), ++ FALSE, 0)) < 0) { ++ AP6211_ERR("%s: Get Capability failed (error=%d)\n", ++ __FUNCTION__, ret); ++ return 0; ++ } ++ if (strstr(buf, "vsdb")) { ++ mchan_supported = TRUE; ++ } ++ if (strstr(buf, "p2p") == NULL) { ++ AP6211_DEBUG("Chip does not support p2p\n"); ++ return 0; ++ } ++ else { ++ /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */ ++ memset(buf, 0, sizeof(buf)); ++ bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), ++ FALSE, 0)) < 0) { ++ AP6211_ERR("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret); ++ return 0; ++ } ++ else { ++ if (buf[0] == 1) { ++ /* By default, chip supports single chan concurrency, ++ * now lets check for mchan ++ */ ++ ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE; ++ if (mchan_supported) ++ ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE; ++#if defined(WL_ENABLE_P2P_IF) ++ /* For customer_hw4, although ICS, ++ * we still support concurrent mode ++ */ ++ return ret; ++#else ++ return 0; ++#endif ++ } ++ } ++ } ++ return 0; ++} ++#endif ++int ++dhd_preinit_ioctls(dhd_pub_t *dhd) ++{ ++ int ret = 0; ++ char eventmask[WL_EVENTING_MASK_LEN]; ++ char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ ++ ++#if !defined(WL_CFG80211) ++ uint up = 0; ++#endif /* !defined(WL_CFG80211) */ ++ uint power_mode = PM_FAST; ++ uint32 dongle_align = DHD_SDALIGN; ++ uint32 glom = CUSTOM_GLOM_SETTING; ++#if defined(VSDB) || defined(ROAM_ENABLE) ++ uint bcn_timeout = 8; ++#else ++ uint bcn_timeout = 4; ++#endif ++#ifdef ENABLE_BCN_LI_BCN_WAKEUP ++ uint32 bcn_li_bcn = 1; ++#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ ++ uint retry_max = 3; ++#if defined(ARP_OFFLOAD_SUPPORT) ++ int arpoe = 1; ++#endif ++ int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME; ++ int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME; ++ int scan_passive_time = DHD_SCAN_PASSIVE_TIME; ++ char buf[WLC_IOCTL_SMLEN]; ++ char *ptr; ++ uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ ++#ifdef ROAM_ENABLE ++ uint roamvar = 0; ++ int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL}; ++ int roam_scan_period[2] = {10, WLC_BAND_ALL}; ++ int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL}; ++#ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC ++ int roam_fullscan_period = 60; ++#else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ ++ int roam_fullscan_period = 120; ++#endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ ++#else ++#ifdef DISABLE_BUILTIN_ROAM ++ uint roamvar = 1; ++#endif /* DISABLE_BUILTIN_ROAM */ ++#endif /* ROAM_ENABLE */ ++ ++#if defined(SOFTAP) ++ uint dtim = 1; ++#endif ++#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) ++ uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ ++ struct ether_addr p2p_ea; ++#endif ++ uint32 mimo_bw_cap = 1; /* Turn HT40 on in 2.4 GHz */ ++ ++#if defined(AP) || defined(WLP2P) ++ uint32 apsta = 1; /* Enable APSTA mode */ ++#endif /* defined(AP) || defined(WLP2P) */ ++#ifdef GET_CUSTOM_MAC_ENABLE ++ struct ether_addr ea_addr; ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++#ifdef DISABLE_11N ++ uint32 nmode = 0; ++#else ++#ifdef AMPDU_HOSTREORDER ++ uint32 hostreorder = 1; ++#endif ++#endif /* DISABLE_11N */ ++ dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM; ++#ifdef PROP_TXSTATUS ++#ifdef PROP_TXSTATUS_VSDB ++ dhd->wlfc_enabled = FALSE; ++ /* enable WLFC only if the firmware is VSDB */ ++#else ++ dhd->wlfc_enabled = TRUE; ++#endif /* PROP_TXSTATUS_VSDB */ ++#endif /* PROP_TXSTATUS */ ++ AP6211_DEBUG("Enter %s\n", __FUNCTION__); ++ dhd->op_mode = 0; ++#ifdef GET_CUSTOM_MAC_ENABLE ++ ret = dhd_custom_get_mac_address(ea_addr.octet); ++ if (!ret) { ++ memset(buf, 0, sizeof(buf)); ++ bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf)); ++ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); ++ if (ret < 0) { ++ AP6211_ERR("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret); ++ return BCME_NOTUP; ++ } ++ memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN); ++ } else { ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++ /* Get the default device MAC address directly from firmware */ ++ memset(buf, 0, sizeof(buf)); ++ bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), ++ FALSE, 0)) < 0) { ++ AP6211_ERR("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret); ++ return BCME_NOTUP; ++ } ++ /* Update public MAC address after reading from Firmware */ ++ memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN); ++ ++#ifdef GET_CUSTOM_MAC_ENABLE ++ } ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++ ++ AP6211_DEBUG("Firmware = %s\n", fw_path); ++ ++ if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || ++ (op_mode == DHD_FLAG_HOSTAP_MODE)) { ++#ifdef SET_RANDOM_MAC_SOFTAP ++ uint rand_mac; ++#endif ++ dhd->op_mode = DHD_FLAG_HOSTAP_MODE; ++#if defined(ARP_OFFLOAD_SUPPORT) ++ arpoe = 0; ++#endif ++#ifdef PKT_FILTER_SUPPORT ++ dhd_pkt_filter_enable = FALSE; ++#endif ++#ifdef SET_RANDOM_MAC_SOFTAP ++ srandom32((uint)jiffies); ++ rand_mac = random32(); ++ iovbuf[0] = 0x02; /* locally administered bit */ ++ iovbuf[1] = 0x1A; ++ iovbuf[2] = 0x11; ++ iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0; ++ iovbuf[4] = (unsigned char)(rand_mac >> 8); ++ iovbuf[5] = (unsigned char)(rand_mac >> 16); ++ ++ bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf)); ++ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); ++ if (ret < 0) { ++ AP6211_ERR("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret); ++ } else ++ memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); ++#endif /* SET_RANDOM_MAC_SOFTAP */ ++#if !defined(AP) && defined(WL_CFG80211) ++ /* Turn off MPC in AP mode */ ++ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, ++ sizeof(iovbuf), TRUE, 0)) < 0) { ++ AP6211_ERR("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret); ++ } ++#endif ++ ++ } ++ else { ++ uint32 concurrent_mode = 0; ++ if ((!op_mode && strstr(fw_path, "_p2p") != NULL) || ++ (op_mode == DHD_FLAG_P2P_MODE)) { ++#if defined(ARP_OFFLOAD_SUPPORT) ++ arpoe = 0; ++#endif ++#ifdef PKT_FILTER_SUPPORT ++ dhd_pkt_filter_enable = FALSE; ++#endif ++ dhd->op_mode = DHD_FLAG_P2P_MODE; ++ } ++ else ++ dhd->op_mode = DHD_FLAG_STA_MODE; ++#if !defined(AP) && defined(WLP2P) ++ if ((concurrent_mode = dhd_get_concurrent_capabilites(dhd))) { ++#if defined(ARP_OFFLOAD_SUPPORT) ++ arpoe = 1; ++#endif ++ dhd->op_mode |= concurrent_mode; ++ } ++ ++ /* Check if we are enabling p2p */ ++ if (dhd->op_mode & DHD_FLAG_P2P_MODE) { ++ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, ++ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { ++ AP6211_ERR("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret); ++ } ++ ++ memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN); ++ ETHER_SET_LOCALADDR(&p2p_ea); ++ bcm_mkiovar("p2p_da_override", (char *)&p2p_ea, ++ ETHER_ADDR_LEN, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, ++ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { ++ AP6211_ERR("%s p2p_da_override ret= %d\n", __FUNCTION__, ret); ++ } else { ++ AP6211_DEBUG("dhd_preinit_ioctls: p2p_da_override succeeded\n"); ++ } ++ } ++#else ++ (void)concurrent_mode; ++#endif ++ } ++ ++ AP6211_ERR("Firmware up: op_mode=0x%04x, " ++ "Broadcom Dongle Host Driver mac="MACDBG"\n", ++ dhd->op_mode, ++ MAC2STRDBG(dhd->mac.octet)); ++ /* Set Country code */ ++ if (dhd->dhd_cspec.ccode[0] != 0) { ++ bcm_mkiovar("country", (char *)&dhd->dhd_cspec, ++ sizeof(wl_country_t), iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) ++ AP6211_ERR("%s: country code setting failed\n", __FUNCTION__); ++ } ++ ++ /* Set Listen Interval */ ++ bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) ++ AP6211_ERR("%s assoc_listen failed %d\n", __FUNCTION__, ret); ++ ++#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM) ++ /* Disable built-in roaming to allowed ext supplicant to take care of roaming */ ++ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */ ++#ifdef ROAM_ENABLE ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger, ++ sizeof(roam_trigger), TRUE, 0)) < 0) ++ AP6211_ERR("%s: roam trigger set failed %d\n", __FUNCTION__, ret); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period, ++ sizeof(roam_scan_period), TRUE, 0)) < 0) ++ AP6211_ERR("%s: roam scan period set failed %d\n", __FUNCTION__, ret); ++ if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta, ++ sizeof(roam_delta), TRUE, 0)) < 0) ++ AP6211_ERR("%s: roam delta set failed %d\n", __FUNCTION__, ret); ++ bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, 4, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) ++ AP6211_ERR("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret); ++#endif /* ROAM_ENABLE */ ++ ++ /* Set PowerSave mode */ ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); ++ ++ /* Match Host and Dongle rx alignment */ ++ bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ ++ if (glom != DEFAULT_GLOM_VALUE) { ++ AP6211_DEBUG("%s set glom=0x%X\n", __FUNCTION__, glom); ++ bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ } ++ ++ /* Setup timeout if Beacons are lost and roam is off to report link down */ ++ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ /* Setup assoc_retry_max count to reconnect target AP in dongle */ ++ bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#if defined(AP) && !defined(WLP2P) ++ /* Turn off MPC in AP mode */ ++ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#endif /* defined(AP) && !defined(WLP2P) */ ++ ++ if (dhd_bus_chip_id(dhd) == BCM43341_CHIP_ID || dhd_bus_chip_id(dhd) == BCM4324_CHIP_ID) { ++ /* Turn on HT40 in 2.4 GHz */ ++ bcm_mkiovar("mimo_bw_cap", (char *)&mimo_bw_cap, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ } ++ ++#if defined(SOFTAP) ++ if (ap_fw_loaded == TRUE) { ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0); ++ } ++#endif ++ ++#if defined(KEEP_ALIVE) ++ { ++ /* Set Keep Alive : be sure to use FW with -keepalive */ ++ int res; ++ ++#if defined(SOFTAP) ++ if (ap_fw_loaded == FALSE) ++#endif ++ if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) { ++ if ((res = dhd_keep_alive_onoff(dhd)) < 0) ++ AP6211_ERR("%s set keeplive failed %d\n", ++ __FUNCTION__, res); ++ } ++ } ++#endif /* defined(KEEP_ALIVE) */ ++ ++ /* Read event_msgs mask */ ++ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) { ++ AP6211_ERR("%s read Event mask failed %d\n", __FUNCTION__, ret); ++ goto done; ++ } ++ bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); ++ ++ /* Setup event_msgs */ ++ setbit(eventmask, WLC_E_SET_SSID); ++ setbit(eventmask, WLC_E_PRUNE); ++ setbit(eventmask, WLC_E_AUTH); ++ setbit(eventmask, WLC_E_ASSOC); ++ setbit(eventmask, WLC_E_REASSOC); ++ setbit(eventmask, WLC_E_REASSOC_IND); ++ setbit(eventmask, WLC_E_DEAUTH); ++ setbit(eventmask, WLC_E_DEAUTH_IND); ++ setbit(eventmask, WLC_E_DISASSOC_IND); ++ setbit(eventmask, WLC_E_DISASSOC); ++ setbit(eventmask, WLC_E_JOIN); ++ setbit(eventmask, WLC_E_ASSOC_IND); ++ setbit(eventmask, WLC_E_PSK_SUP); ++ setbit(eventmask, WLC_E_LINK); ++ setbit(eventmask, WLC_E_NDIS_LINK); ++ setbit(eventmask, WLC_E_MIC_ERROR); ++ setbit(eventmask, WLC_E_ASSOC_REQ_IE); ++ setbit(eventmask, WLC_E_ASSOC_RESP_IE); ++#ifndef WL_CFG80211 ++ setbit(eventmask, WLC_E_PMKID_CACHE); ++ setbit(eventmask, WLC_E_TXFAIL); ++#endif ++ setbit(eventmask, WLC_E_JOIN_START); ++ setbit(eventmask, WLC_E_SCAN_COMPLETE); ++#ifdef WLMEDIA_HTSF ++ setbit(eventmask, WLC_E_HTSFSYNC); ++#endif /* WLMEDIA_HTSF */ ++#ifdef PNO_SUPPORT ++ setbit(eventmask, WLC_E_PFN_NET_FOUND); ++#endif /* PNO_SUPPORT */ ++ /* enable dongle roaming event */ ++ setbit(eventmask, WLC_E_ROAM); ++#ifdef WL_CFG80211 ++ setbit(eventmask, WLC_E_ESCAN_RESULT); ++ if (dhd->op_mode & DHD_FLAG_P2P_MODE) { ++ setbit(eventmask, WLC_E_ACTION_FRAME_RX); ++ setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE); ++ } ++#endif /* WL_CFG80211 */ ++ ++ /* Write updated Event mask */ ++ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { ++ AP6211_ERR("%s Set Event mask failed %d\n", __FUNCTION__, ret); ++ goto done; ++ } ++ ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time, ++ sizeof(scan_assoc_time), TRUE, 0); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, ++ sizeof(scan_unassoc_time), TRUE, 0); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time, ++ sizeof(scan_passive_time), TRUE, 0); ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ /* Set and enable ARP offload feature for STA only */ ++#if defined(SOFTAP) ++ if (arpoe && !ap_fw_loaded) { ++#else ++ if (arpoe) { ++#endif ++ dhd_arp_offload_enable(dhd, TRUE); ++ dhd_arp_offload_set(dhd, dhd_arp_mode); ++ } else { ++ dhd_arp_offload_enable(dhd, FALSE); ++ dhd_arp_offload_set(dhd, 0); ++ } ++ dhd_arp_enable = arpoe; ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++#ifdef PKT_FILTER_SUPPORT ++ /* Setup default defintions for pktfilter , enable in suspend */ ++ dhd->pktfilter_count = 5; ++ /* Setup filter to allow only unicast */ ++ dhd->pktfilter[0] = "100 0 0 0 0x01 0x00"; ++ dhd->pktfilter[1] = NULL; ++ dhd->pktfilter[2] = NULL; ++ dhd->pktfilter[3] = NULL; ++ /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */ ++ dhd->pktfilter[4] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB"; ++ dhd_set_packet_filter(dhd); ++ ++#if defined(SOFTAP) ++ if (ap_fw_loaded) { ++ dhd_enable_packet_filter(0, dhd); ++ } ++#endif /* defined(SOFTAP) */ ++ ++#endif /* PKT_FILTER_SUPPORT */ ++#ifdef DISABLE_11N ++ bcm_mkiovar("nmode", (char *)&nmode, 4, iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) ++ AP6211_ERR("%s wl nmode 0 failed %d\n", __FUNCTION__, ret); ++#else ++#ifdef AMPDU_HOSTREORDER ++ bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, buf, sizeof(buf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); ++#endif /* AMPDU_HOSTREORDER */ ++#endif /* DISABLE_11N */ ++ ++#if !defined(WL_CFG80211) ++ /* Force STA UP */ ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0)) < 0) { ++ AP6211_ERR("%s Setting WL UP failed %d\n", __FUNCTION__, ret); ++ goto done; ++ } ++#endif ++ ++#ifdef ENABLE_BCN_LI_BCN_WAKEUP ++ bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ ++ ++ /* query for 'ver' to get version info from firmware */ ++ memset(buf, 0, sizeof(buf)); ++ ptr = buf; ++ bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0) ++ AP6211_ERR("%s failed %d\n", __FUNCTION__, ret); ++ else { ++ bcmstrtok(&ptr, "\n", 0); ++ /* Print fw version info */ ++ AP6211_ERR("Firmware version = %s\n", buf); ++ ++ dhd_set_version_info(dhd, buf); ++ ++ DHD_BLOG(buf, strlen(buf) + 1); ++ DHD_BLOG(dhd_version, strlen(dhd_version) + 1); ++ DHD_BLOG(dhd_version_info, strlen(dhd_version_info) +1); ++ ++ /* Check and adjust IOCTL response timeout for Manufactring firmware */ ++ if (strstr(buf, MANUFACTRING_FW) != NULL) { ++ dhd_os_set_ioctl_resp_timeout(20000); ++ AP6211_ERR("%s : adjust IOCTL response time for Manufactring Firmware\n", ++ __FUNCTION__); ++ } ++ } ++ ++done: ++ return ret; ++} ++ ++ ++int ++dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set) ++{ ++ char buf[strlen(name) + 1 + cmd_len]; ++ int len = sizeof(buf); ++ wl_ioctl_t ioc; ++ int ret; ++ ++ len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len); ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ++ ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR; ++ ioc.buf = buf; ++ ioc.len = len; ++ ioc.set = TRUE; ++ ++ ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); ++ if (!set && ret >= 0) ++ memcpy(cmd_buf, buf, cmd_len); ++ ++ return ret; ++} ++ ++int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx) ++{ ++ struct dhd_info *dhd = dhdp->info; ++ struct net_device *dev = NULL; ++ ++ ASSERT(dhd && dhd->iflist[ifidx]); ++ dev = dhd->iflist[ifidx]->net; ++ ASSERT(dev); ++ ++ if (netif_running(dev)) { ++ AP6211_ERR("%s: Must be down to change its MTU", dev->name); ++ return BCME_NOTDOWN; ++ } ++ ++#define DHD_MIN_MTU 1500 ++#define DHD_MAX_MTU 1752 ++ ++ if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) { ++ AP6211_ERR("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu); ++ return BCME_BADARG; ++ } ++ ++ dev->mtu = new_mtu; ++ return 0; ++} ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */ ++void ++aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx) ++{ ++ u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */ ++ int i; ++ int ret; ++ ++ bzero(ipv4_buf, sizeof(ipv4_buf)); ++ ++ /* display what we've got */ ++ ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); ++ AP6211_DEBUG("%s: hostip table read from Dongle:\n", __FUNCTION__); ++#ifdef AOE_DBG ++ dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ ++#endif ++ /* now we saved hoste_ip table, clr it in the dongle AOE */ ++ dhd_aoe_hostip_clr(dhd_pub, idx); ++ ++ if (ret) { ++ AP6211_ERR("%s failed\n", __FUNCTION__); ++ return; ++ } ++ ++ for (i = 0; i < MAX_IPV4_ENTRIES; i++) { ++ if (add && (ipv4_buf[i] == 0)) { ++ ipv4_buf[i] = ipa; ++ add = FALSE; /* added ipa to local table */ ++ AP6211_DEBUG("%s: Saved new IP in temp arp_hostip[%d]\n", ++ __FUNCTION__, i); ++ } else if (ipv4_buf[i] == ipa) { ++ ipv4_buf[i] = 0; ++ AP6211_DEBUG("%s: removed IP:%x from temp table %d\n", ++ __FUNCTION__, ipa, i); ++ } ++ ++ if (ipv4_buf[i] != 0) { ++ /* add back host_ip entries from our local cache */ ++ dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i], idx); ++ AP6211_DEBUG("%s: added IP:%x to dongle arp_hostip[%d]\n\n", ++ __FUNCTION__, ipv4_buf[i], i); ++ } ++ } ++#ifdef AOE_DBG ++ /* see the resulting hostip table */ ++ dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); ++ AP6211_DEBUG("%s: read back arp_hostip table:\n", __FUNCTION__); ++ dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ ++#endif ++} ++ ++/* ++ * Notification mechanism from kernel to our driver. This function is called by the Linux kernel ++ * whenever there is an event related to an IP address. ++ * ptr : kernel provided pointer to IP address that has changed ++ */ ++static int dhd_device_event(struct notifier_block *this, ++ unsigned long event, ++ void *ptr) ++{ ++ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; ++ ++ dhd_info_t *dhd; ++ dhd_pub_t *dhd_pub; ++ int idx; ++ ++ if (!dhd_arp_enable) ++ return NOTIFY_DONE; ++ if (!ifa || !(ifa->ifa_dev->dev)) ++ return NOTIFY_DONE; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) ++ /* Filter notifications meant for non Broadcom devices */ ++ if ((ifa->ifa_dev->dev->netdev_ops != &dhd_ops_pri) && ++ (ifa->ifa_dev->dev->netdev_ops != &dhd_ops_virt)) { ++#ifdef WLP2P ++ if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops)) ++#endif ++ return NOTIFY_DONE; ++ } ++#endif /* LINUX_VERSION_CODE */ ++ ++ dhd = *(dhd_info_t **)netdev_priv(ifa->ifa_dev->dev); ++ if (!dhd) ++ return NOTIFY_DONE; ++ ++ dhd_pub = &dhd->pub; ++ ++ if (dhd_pub->arp_version == 1) { ++ idx = 0; ++ } ++ else { ++ for (idx = 0; idx < DHD_MAX_IFS; idx++) { ++ if (dhd->iflist[idx] && dhd->iflist[idx]->net == ifa->ifa_dev->dev) ++ break; ++ } ++ if (idx < DHD_MAX_IFS) ++ AP6211_DEBUG("ifidx : %p %s %d\n", dhd->iflist[idx]->net, ++ dhd->iflist[idx]->name, dhd->iflist[idx]->idx); ++ else { ++ AP6211_ERR("Cannot find ifidx for(%s) set to 0\n", ifa->ifa_label); ++ idx = 0; ++ } ++ } ++ ++ switch (event) { ++ case NETDEV_UP: ++ AP6211_DEBUG("%s: [%s] Up IP: 0x%x\n", ++ __FUNCTION__, ifa->ifa_label, ifa->ifa_address); ++ ++ if (dhd->pub.busstate != DHD_BUS_DATA) { ++ AP6211_ERR("%s: bus not ready, exit\n", __FUNCTION__); ++ if (dhd->pend_ipaddr) { ++ AP6211_ERR("%s: overwrite pending ipaddr: 0x%x\n", ++ __FUNCTION__, dhd->pend_ipaddr); ++ } ++ dhd->pend_ipaddr = ifa->ifa_address; ++ break; ++ } ++ ++#ifdef AOE_IP_ALIAS_SUPPORT ++ AP6211_DEBUG("%s:add aliased IP to AOE hostip cache\n", ++ __FUNCTION__); ++ aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE, idx); ++#endif ++ break; ++ ++ case NETDEV_DOWN: ++ AP6211_DEBUG("%s: [%s] Down IP: 0x%x\n", ++ __FUNCTION__, ifa->ifa_label, ifa->ifa_address); ++ dhd->pend_ipaddr = 0; ++#ifdef AOE_IP_ALIAS_SUPPORT ++ AP6211_DEBUG("%s:interface is down, AOE clr all for this if\n", ++ __FUNCTION__); ++ aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx); ++#else ++ dhd_aoe_hostip_clr(&dhd->pub, idx); ++ dhd_aoe_arp_clr(&dhd->pub, idx); ++#endif /* AOE_IP_ALIAS_SUPPORT */ ++ break; ++ ++ default: ++ AP6211_DEBUG("%s: do noting for [%s] Event: %lu\n", ++ __func__, ifa->ifa_label, event); ++ break; ++ } ++ return NOTIFY_DONE; ++} ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++int ++dhd_net_attach(dhd_pub_t *dhdp, int ifidx) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ struct net_device *net = NULL; ++ int err = 0; ++ uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 }; ++ ++ AP6211_DEBUG("%s: ifidx %d\n", __FUNCTION__, ifidx); ++ ++ ASSERT(dhd && dhd->iflist[ifidx]); ++ ++ net = dhd->iflist[ifidx]->net; ++ ASSERT(net); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ++ ASSERT(!net->open); ++ net->get_stats = dhd_get_stats; ++ net->do_ioctl = dhd_ioctl_entry; ++ net->hard_start_xmit = dhd_start_xmit; ++ net->set_mac_address = dhd_set_mac_address; ++ net->set_multicast_list = dhd_set_multicast_list; ++ net->open = net->stop = NULL; ++#else ++ ASSERT(!net->netdev_ops); ++ net->netdev_ops = &dhd_ops_virt; ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ ++ ++ /* Ok, link into the network layer... */ ++ if (ifidx == 0) { ++ /* ++ * device functions for the primary interface only ++ */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ++ net->open = dhd_open; ++ net->stop = dhd_stop; ++#else ++ net->netdev_ops = &dhd_ops_pri; ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ ++ if (!ETHER_ISNULLADDR(dhd->pub.mac.octet)) ++ memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); ++ } else { ++ /* ++ * We have to use the primary MAC for virtual interfaces ++ */ ++ memcpy(temp_addr, dhd->iflist[ifidx]->mac_addr, ETHER_ADDR_LEN); ++ /* ++ * Android sets the locally administered bit to indicate that this is a ++ * portable hotspot. This will not work in simultaneous AP/STA mode, ++ * nor with P2P. Need to set the Donlge's MAC address, and then use that. ++ */ ++ if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr, ++ ETHER_ADDR_LEN)) { ++ AP6211_ERR("%s interface [%s]: set locally administered bit in MAC\n", ++ __func__, net->name); ++ temp_addr[0] |= 0x02; ++ } ++ } ++ ++ net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) ++ net->ethtool_ops = &dhd_ethtool_ops; ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ ++ ++#if defined(CONFIG_WIRELESS_EXT) ++#if WIRELESS_EXT < 19 ++ net->get_wireless_stats = dhd_get_wireless_stats; ++#endif /* WIRELESS_EXT < 19 */ ++#if WIRELESS_EXT > 12 ++ net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def; ++#endif /* WIRELESS_EXT > 12 */ ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++ dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); ++ ++ memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); ++ ++ if ((err = register_netdev(net)) != 0) { ++ AP6211_ERR("couldn't register the net device, err %d\n", err); ++ goto fail; ++ } ++ AP6211_ERR("Broadcom Dongle Host Driver: register interface [%s] MAC: "MACDBG"\n", ++ net->name, ++ MAC2STRDBG(net->dev_addr)); ++ ++#if defined(SOFTAP) && defined(CONFIG_WIRELESS_EXT) && !defined(WL_CFG80211) ++ wl_iw_iscan_set_scan_broadcast_prep(net, 1); ++#endif ++ ++#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ if (ifidx == 0) { ++ dhd_registration_check = TRUE; ++ up(&dhd_registration_sem); ++ } ++#endif ++ return 0; ++ ++fail: ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) ++ net->open = NULL; ++#else ++ net->netdev_ops = NULL; ++#endif ++ return err; ++} ++ ++void ++dhd_bus_detach(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (dhdp) { ++ dhd = (dhd_info_t *)dhdp->info; ++ if (dhd) { ++ ++ /* ++ * In case of Android cfg80211 driver, the bus is down in dhd_stop, ++ * calling stop again will cuase SD read/write errors. ++ */ ++ if (dhd->pub.busstate != DHD_BUS_DOWN) { ++ /* Stop the protocol module */ ++ dhd_prot_stop(&dhd->pub); ++ ++ /* Stop the bus module */ ++ dhd_bus_stop(dhd->pub.bus, TRUE); ++ } ++ ++#if defined(OOB_INTR_ONLY) ++ bcmsdh_unregister_oob_intr(); ++#endif ++ } ++ } ++} ++ ++ ++void dhd_detach(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd; ++ unsigned long flags; ++ int timer_valid = FALSE; ++ ++ if (!dhdp) ++ return; ++ ++ dhd = (dhd_info_t *)dhdp->info; ++ if (!dhd) ++ return; ++ ++ AP6211_DEBUG("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state); ++#ifdef ARP_OFFLOAD_SUPPORT ++ unregister_inetaddr_notifier(&dhd_notifier); ++#endif /* ARP_OFFLOAD_SUPPORT */ ++#ifdef IPV6 ++ unregister_inet6addr_notifier(&dhd_notifier_ipv6); ++#endif ++ ++ dhd->pub.up = 0; ++ if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) { ++ /* Give sufficient time for threads to start running in case ++ * dhd_attach() has failed ++ */ ++ osl_delay(1000*100); ++ } ++ ++ if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) { ++ dhd_bus_detach(dhdp); ++ ++ if (dhdp->prot) ++ dhd_prot_detach(dhdp); ++ } ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ unregister_inetaddr_notifier(&dhd_notifier); ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++ if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) { ++ if (dhd->early_suspend.suspend) ++ unregister_early_suspend(&dhd->early_suspend); ++ } ++#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ cancel_work_sync(&dhd->work_hang); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++ ++#if defined(CONFIG_WIRELESS_EXT) ++ if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) { ++ /* Detatch and unlink in the iw */ ++ wl_iw_detach(); ++ } ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++ if (dhd->thr_sysioc_ctl.thr_pid >= 0) { ++ PROC_STOP(&dhd->thr_sysioc_ctl); ++ } ++ ++ /* delete all interfaces, start with virtual */ ++ if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) { ++ int i = 1; ++ dhd_if_t *ifp; ++ ++ /* Cleanup virtual interfaces */ ++ for (i = 1; i < DHD_MAX_IFS; i++) { ++ dhd_net_if_lock_local(dhd); ++ if (dhd->iflist[i]) { ++ dhd->iflist[i]->state = DHD_IF_DEL; ++ dhd->iflist[i]->idx = i; ++ dhd_op_if(dhd->iflist[i]); ++ } ++ ++ dhd_net_if_unlock_local(dhd); ++ } ++ /* delete primary interface 0 */ ++ ifp = dhd->iflist[0]; ++ ASSERT(ifp); ++ ASSERT(ifp->net); ++ if (ifp && ifp->net) { ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ++ if (ifp->net->open) ++#else ++ if (ifp->net->netdev_ops == &dhd_ops_pri) ++#endif ++ { ++ unregister_netdev(ifp->net); ++ free_netdev(ifp->net); ++ ifp->net = NULL; ++ MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); ++ dhd->iflist[0] = NULL; ++ } ++ } ++ } ++ ++ /* Clear the watchdog timer */ ++ flags = dhd_os_spin_lock(&dhd->pub); ++ timer_valid = dhd->wd_timer_valid; ++ dhd->wd_timer_valid = FALSE; ++ dhd_os_spin_unlock(&dhd->pub, flags); ++ if (timer_valid) ++ del_timer_sync(&dhd->timer); ++ ++ if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) { ++#ifdef DHDTHREAD ++ if (dhd->thr_wdt_ctl.thr_pid >= 0) { ++ PROC_STOP(&dhd->thr_wdt_ctl); ++ } ++ ++ if (dhd->thr_dpc_ctl.thr_pid >= 0) { ++ PROC_STOP(&dhd->thr_dpc_ctl); ++ } ++ else ++#endif /* DHDTHREAD */ ++ tasklet_kill(&dhd->tasklet); ++ } ++ ++#ifdef WL_CFG80211 ++ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { ++ wl_cfg80211_detach(NULL); ++ dhd_monitor_uninit(); ++ } ++#endif ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) ++ unregister_pm_notifier(&dhd_sleep_pm_notifier); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ ++ /* && defined(CONFIG_PM_SLEEP) */ ++ ++ if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) { ++#ifdef CONFIG_HAS_WAKELOCK ++ dhd->wakelock_counter = 0; ++ dhd->wakelock_wd_counter = 0; ++ dhd->wakelock_rx_timeout_enable = 0; ++ dhd->wakelock_ctrl_timeout_enable = 0; ++ if (dhd->wl_wifi) { ++ wake_lock_destroy(dhd->wl_wifi); ++ MFREE(dhd->pub.osh, dhd->wl_wifi, sizeof(struct wake_lock)); ++ dhd->wl_wifi = NULL; ++ } ++ if (dhd->wl_rxwake) { ++ wake_lock_destroy(dhd->wl_rxwake); ++ MFREE(dhd->pub.osh, dhd->wl_rxwake, sizeof(struct wake_lock)); ++ dhd->wl_rxwake = NULL; ++ } ++ if (dhd->wl_ctrlwake) { ++ wake_lock_destroy(dhd->wl_ctrlwake); ++ MFREE(dhd->pub.osh, dhd->wl_ctrlwake, sizeof(struct wake_lock)); ++ dhd->wl_ctrlwake = NULL; ++ } ++ if (dhd->wl_wdwake) { ++ wake_lock_destroy(dhd->wl_wdwake); ++ MFREE(dhd->pub.osh, dhd->wl_wdwake, sizeof(struct wake_lock)); ++ dhd->wl_wdwake = NULL; ++ } ++#endif /* CONFIG_HAS_WAKELOCK */ ++ } ++} ++ ++ ++void ++dhd_free(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd; ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (dhdp) { ++ int i; ++ for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) { ++ if (dhdp->reorder_bufs[i]) { ++ reorder_info_t *ptr; ++ uint32 buf_size = sizeof(struct reorder_info); ++ ++ ptr = dhdp->reorder_bufs[i]; ++ ++ buf_size += ((ptr->max_idx + 1) * sizeof(void*)); ++ AP6211_DEBUG("free flow id buf %d, maxidx is %d, buf_size %d\n", ++ i, ptr->max_idx, buf_size); ++ ++ MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size); ++ dhdp->reorder_bufs[i] = NULL; ++ } ++ } ++ dhd = (dhd_info_t *)dhdp->info; ++ if (dhd) ++ MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); ++ } ++} ++ ++static void __exit ++dhd_module_cleanup(void) ++{ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ dhd_bus_unregister(); ++ ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++ wl_android_wifictrl_func_del(); ++#endif /* CONFIG_WIFI_CONTROL_FUNC */ ++ wl_android_exit(); ++ ++ /* Call customer gpio to turn off power with WL_REG_ON signal */ ++ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); ++ ++ if (wl_host_wake > 0) ++ gpio_free(wl_host_wake); ++ wl_host_wake = -1; ++ ++ /*sw_rfkill_exit(); The comment must remove when we use the Bluetooth*/ ++ ap6211_gpio_wifi_exit(); ++} ++ ++ ++static int __init ++dhd_module_init(void) ++{ ++ int error = 0; ++ ++#if 1 && defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ int retry = POWERUP_MAX_RETRY; ++ int chip_up = 0; ++#endif ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ AP6211_INFO("--->The Drive has been modified for BananaPro by LeMaker team<---\n"); ++ ++ ap6211_gpio_wifi_init(); ++ /*sw_rfkill_init(); The comment must remove when we use the Bluetooth*/ ++ ++ if (gpio_request(WL_HOST_WAKE_DEF_GPIO, "wl_host_wake")) { ++ AP6211_ERR("[%s] get wl_host_wake gpio failed\n", __FUNCTION__); ++ wl_host_wake = -1; ++ return -1; ++ } ++ wl_host_wake = WL_HOST_WAKE_DEF_GPIO; ++ gpio_direction_input(wl_host_wake); ++ wl_host_wake_irqno = gpio_to_irq(wl_host_wake); ++ AP6211_DEBUG("got gpio%d, mapped to irqno%d\n", wl_host_wake, wl_host_wake_irqno); ++ ++ wl_android_init(); ++ ++#if defined(DHDTHREAD) ++ /* Sanity check on the module parameters */ ++ do { ++ /* Both watchdog and DPC as tasklets are ok */ ++ if ((dhd_watchdog_prio < 0) && (dhd_dpc_prio < 0)) ++ break; ++ ++ /* If both watchdog and DPC are threads, TX must be deferred */ ++ if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0) && dhd_deferred_tx) ++ break; ++ ++ AP6211_ERR("Invalid module parameters.\n"); ++ return -EINVAL; ++ } while (0); ++#endif ++ ++#if 1 && defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ do { ++ sema_init(&dhd_chipup_sem, 0); ++ dhd_bus_reg_sdio_notify(&dhd_chipup_sem); ++ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++ if (wl_android_wifictrl_func_add() < 0) { ++ dhd_bus_unreg_sdio_notify(); ++ goto fail_1; ++ } ++#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ ++ if (down_timeout(&dhd_chipup_sem, ++ msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) { ++ dhd_bus_unreg_sdio_notify(); ++ chip_up = 1; ++ break; ++ } ++ AP6211_ERR("failed to power up wifi chip, retry again (%d left) **\n\n", ++ retry+1); ++ dhd_bus_unreg_sdio_notify(); ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++ wl_android_wifictrl_func_del(); ++#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ ++ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); ++ } while (retry-- > 0); ++ ++ if (!chip_up) { ++ AP6211_ERR("failed to power up wifi chip, max retry reached, exits **\n\n"); ++ return -ENODEV; ++ } ++#else ++ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++ if (wl_android_wifictrl_func_add() < 0) ++ goto fail_1; ++#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ ++ ++#endif ++ ++#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ sema_init(&dhd_registration_sem, 0); ++#endif ++ ++ ++ error = dhd_bus_register(); ++ ++ if (!error) ++ AP6211_DEBUG("%s\n", dhd_version); ++ else { ++ AP6211_ERR("%s: sdio_register_driver failed\n", __FUNCTION__); ++ goto fail_1; ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ /* ++ * Wait till MMC sdio_register_driver callback called and made driver attach. ++ * It's needed to make sync up exit from dhd insmod and ++ * Kernel MMC sdio device callback registration ++ */ ++ if ((down_timeout(&dhd_registration_sem, ++ msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) || ++ (dhd_registration_check != TRUE)) { ++ error = -ENODEV; ++ AP6211_ERR("%s: sdio_register_driver timeout or error \n", __FUNCTION__); ++ goto fail_2; ++ } ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++#if defined(WL_CFG80211) ++ wl_android_post_init(); ++#endif /* defined(WL_CFG80211) */ ++ ++ return error; ++ ++#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++fail_2: ++ dhd_bus_unregister(); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++ ++fail_1: ++ ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++ wl_android_wifictrl_func_del(); ++#endif ++ ++ /* Call customer gpio to turn off power with WL_REG_ON signal */ ++ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); ++ ++ return error; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++late_initcall(dhd_module_init); ++#else ++module_init(dhd_module_init); ++#endif ++ ++module_exit(dhd_module_cleanup); ++ ++/* ++ * OS specific functions required to implement DHD driver in OS independent way ++ */ ++int ++dhd_os_proto_block(dhd_pub_t *pub) ++{ ++ dhd_info_t * dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++ down(&dhd->proto_sem); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++int ++dhd_os_proto_unblock(dhd_pub_t *pub) ++{ ++ dhd_info_t * dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++ up(&dhd->proto_sem); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++unsigned int ++dhd_os_get_ioctl_resp_timeout(void) ++{ ++ return ((unsigned int)dhd_ioctl_timeout_msec); ++} ++ ++void ++dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec) ++{ ++ dhd_ioctl_timeout_msec = (int)timeout_msec; ++} ++ ++int ++dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) ++{ ++ dhd_info_t * dhd = (dhd_info_t *)(pub->info); ++ int timeout; ++ ++ /* Convert timeout in millsecond to jiffies */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); ++#else ++ timeout = dhd_ioctl_timeout_msec * HZ / 1000; ++#endif ++ ++ timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout); ++ return timeout; ++} ++ ++int ++dhd_os_ioctl_resp_wake(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ if (waitqueue_active(&dhd->ioctl_resp_wait)) { ++ wake_up(&dhd->ioctl_resp_wait); ++ } ++ ++ return 0; ++} ++ ++void ++dhd_os_wd_timer(void *bus, uint wdtick) ++{ ++ dhd_pub_t *pub = bus; ++ dhd_info_t *dhd = (dhd_info_t *)pub->info; ++ unsigned long flags; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (!dhd) ++ return; ++ if (wdtick) ++ DHD_OS_WD_WAKE_LOCK(pub); ++ ++ flags = dhd_os_spin_lock(pub); ++ ++ /* don't start the wd until fw is loaded */ ++ if (pub->busstate == DHD_BUS_DOWN) { ++ dhd_os_spin_unlock(pub, flags); ++ DHD_OS_WD_WAKE_UNLOCK(pub); ++ return; ++ } ++ ++ /* totally stop the timer */ ++ if (!wdtick && dhd->wd_timer_valid == TRUE) { ++ dhd->wd_timer_valid = FALSE; ++ dhd_os_spin_unlock(pub, flags); ++#ifdef DHDTHREAD ++ del_timer_sync(&dhd->timer); ++#else ++ del_timer(&dhd->timer); ++#endif /* DHDTHREAD */ ++ /* Unlock when timer deleted */ ++ DHD_OS_WD_WAKE_UNLOCK(pub); ++ return; ++ } ++ ++ if (wdtick) { ++ dhd_watchdog_ms = (uint)wdtick; ++ /* Re arm the timer, at last watchdog period */ ++ mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); ++ dhd->wd_timer_valid = TRUE; ++ } ++ dhd_os_spin_unlock(pub, flags); ++} ++ ++void * ++dhd_os_open_image(char *filename) ++{ ++ struct file *fp; ++ ++ fp = filp_open(filename, O_RDONLY, 0); ++ /* ++ * 2.6.11 (FC4) supports filp_open() but later revs don't? ++ * Alternative: ++ * fp = open_namei(AT_FDCWD, filename, O_RD, 0); ++ * ??? ++ */ ++ if (IS_ERR(fp)) ++ fp = NULL; ++ ++ return fp; ++} ++ ++int ++dhd_os_get_image_block(char *buf, int len, void *image) ++{ ++ struct file *fp = (struct file *)image; ++ int rdlen; ++ ++ if (!image) ++ return 0; ++ ++ rdlen = kernel_read(fp, fp->f_pos, buf, len); ++ if (rdlen > 0) ++ fp->f_pos += rdlen; ++ ++ return rdlen; ++} ++ ++void ++dhd_os_close_image(void *image) ++{ ++ if (image) ++ filp_close((struct file *)image, NULL); ++} ++ ++ ++void ++dhd_os_sdlock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)(pub->info); ++ ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ down(&dhd->sdsem); ++ else ++#endif /* DHDTHREAD */ ++ spin_lock_bh(&dhd->sdlock); ++} ++ ++void ++dhd_os_sdunlock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)(pub->info); ++ ++#ifdef DHDTHREAD ++ if (dhd->threads_only) ++ up(&dhd->sdsem); ++ else ++#endif /* DHDTHREAD */ ++ spin_unlock_bh(&dhd->sdlock); ++} ++ ++void ++dhd_os_sdlock_txq(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)(pub->info); ++ spin_lock_bh(&dhd->txqlock); ++} ++ ++void ++dhd_os_sdunlock_txq(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)(pub->info); ++ spin_unlock_bh(&dhd->txqlock); ++} ++ ++void ++dhd_os_sdlock_rxq(dhd_pub_t *pub) ++{ ++} ++ ++void ++dhd_os_sdunlock_rxq(dhd_pub_t *pub) ++{ ++} ++ ++void ++dhd_os_sdtxlock(dhd_pub_t *pub) ++{ ++ dhd_os_sdlock(pub); ++} ++ ++void ++dhd_os_sdtxunlock(dhd_pub_t *pub) ++{ ++ dhd_os_sdunlock(pub); ++} ++ ++#if defined(CONFIG_DHD_USE_STATIC_BUF) ++uint8* dhd_os_prealloc(void *osh, int section, uint size) ++{ ++ return (uint8*)wl_android_prealloc(section, size); ++} ++ ++void dhd_os_prefree(void *osh, void *addr, uint size) ++{ ++} ++#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ ++ ++#if defined(CONFIG_WIRELESS_EXT) ++struct iw_statistics * ++dhd_get_wireless_stats(struct net_device *dev) ++{ ++ int res = 0; ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ if (!dhd->pub.up) { ++ return NULL; ++ } ++ ++ res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats); ++ ++ if (res == 0) ++ return &dhd->iw.wstats; ++ else ++ return NULL; ++} ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++static int ++dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, ++ wl_event_msg_t *event, void **data) ++{ ++ int bcmerror = 0; ++ ASSERT(dhd != NULL); ++ ++ bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data); ++ if (bcmerror != BCME_OK) ++ return (bcmerror); ++ ++#if defined(CONFIG_WIRELESS_EXT) ++ if (event->bsscfgidx == 0) { ++ /* ++ * Wireless ext is on primary interface only ++ */ ++ ++ ASSERT(dhd->iflist[*ifidx] != NULL); ++ ASSERT(dhd->iflist[*ifidx]->net != NULL); ++ ++ if (dhd->iflist[*ifidx]->net) { ++ wl_iw_event(dhd->iflist[*ifidx]->net, event, *data); ++ } ++ } ++#endif /* defined(CONFIG_WIRELESS_EXT) */ ++ ++#ifdef WL_CFG80211 ++ if ((ntoh32(event->event_type) == WLC_E_IF) && ++ (((dhd_if_event_t *)*data)->action == WLC_E_IF_ADD)) ++ /* If ADD_IF has been called directly by wl utility then we ++ * should not report this. In case if ADD_IF was called from ++ * CFG stack, then too this event need not be reported back ++ */ ++ return (BCME_OK); ++ if ((wl_cfg80211_is_progress_ifchange() || ++ wl_cfg80211_is_progress_ifadd()) && (*ifidx != 0)) { ++ /* ++ * If IF_ADD/CHANGE operation is going on, ++ * discard any event received on the virtual I/F ++ */ ++ return (BCME_OK); ++ } ++ ++ ASSERT(dhd->iflist[*ifidx] != NULL); ++ ASSERT(dhd->iflist[*ifidx]->net != NULL); ++ if (dhd->iflist[*ifidx]->event2cfg80211 && dhd->iflist[*ifidx]->net) { ++ wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data); ++ } ++#endif /* defined(WL_CFG80211) */ ++ ++ return (bcmerror); ++} ++ ++/* send up locally generated event */ ++void ++dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) ++{ ++ switch (ntoh32(event->event_type)) { ++#ifdef WLBTAMP ++ /* Send up locally generated AMP HCI Events */ ++ case WLC_E_BTA_HCI_EVENT: { ++ struct sk_buff *p, *skb; ++ bcm_event_t *msg; ++ wl_event_msg_t *p_bcm_event; ++ char *ptr; ++ uint32 len; ++ uint32 pktlen; ++ dhd_if_t *ifp; ++ dhd_info_t *dhd; ++ uchar *eth; ++ int ifidx; ++ ++ len = ntoh32(event->datalen); ++ pktlen = sizeof(bcm_event_t) + len + 2; ++ dhd = dhdp->info; ++ ifidx = dhd_ifname2idx(dhd, event->ifname); ++ ++ if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) { ++ ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32))); ++ ++ msg = (bcm_event_t *) PKTDATA(dhdp->osh, p); ++ ++ bcopy(&dhdp->mac, &msg->eth.ether_dhost, ETHER_ADDR_LEN); ++ bcopy(&dhdp->mac, &msg->eth.ether_shost, ETHER_ADDR_LEN); ++ ETHER_TOGGLE_LOCALADDR(&msg->eth.ether_shost); ++ ++ msg->eth.ether_type = hton16(ETHER_TYPE_BRCM); ++ ++ /* BCM Vendor specific header... */ ++ msg->bcm_hdr.subtype = hton16(BCMILCP_SUBTYPE_VENDOR_LONG); ++ msg->bcm_hdr.version = BCMILCP_BCM_SUBTYPEHDR_VERSION; ++ bcopy(BRCM_OUI, &msg->bcm_hdr.oui[0], DOT11_OUI_LEN); ++ ++ /* vendor spec header length + pvt data length (private indication ++ * hdr + actual message itself) ++ */ ++ msg->bcm_hdr.length = hton16(BCMILCP_BCM_SUBTYPEHDR_MINLENGTH + ++ BCM_MSG_LEN + sizeof(wl_event_msg_t) + (uint16)len); ++ msg->bcm_hdr.usr_subtype = hton16(BCMILCP_BCM_SUBTYPE_EVENT); ++ ++ PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2)); ++ ++ /* copy wl_event_msg_t into sk_buf */ ++ ++ /* pointer to wl_event_msg_t in sk_buf */ ++ p_bcm_event = &msg->event; ++ bcopy(event, p_bcm_event, sizeof(wl_event_msg_t)); ++ ++ /* copy hci event into sk_buf */ ++ bcopy(data, (p_bcm_event + 1), len); ++ ++ msg->bcm_hdr.length = hton16(sizeof(wl_event_msg_t) + ++ ntoh16(msg->bcm_hdr.length)); ++ PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2)); ++ ++ ptr = (char *)(msg + 1); ++ /* Last 2 bytes of the message are 0x00 0x00 to signal that there ++ * are no ethertypes which are following this ++ */ ++ ptr[len+0] = 0x00; ++ ptr[len+1] = 0x00; ++ ++ skb = PKTTONATIVE(dhdp->osh, p); ++ eth = skb->data; ++ len = skb->len; ++ ++ ifp = dhd->iflist[ifidx]; ++ if (ifp == NULL) ++ ifp = dhd->iflist[0]; ++ ++ ASSERT(ifp); ++ skb->dev = ifp->net; ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ ++ skb->data = eth; ++ skb->len = len; ++ ++ /* Strip header, count, deliver upward */ ++ skb_pull(skb, ETH_HLEN); ++ ++ /* Send the packet */ ++ if (in_interrupt()) { ++ netif_rx(skb); ++ } else { ++ netif_rx_ni(skb); ++ } ++ } ++ else { ++ /* Could not allocate a sk_buf */ ++ AP6211_ERR("%s: unable to alloc sk_buf", __FUNCTION__); ++ } ++ break; ++ } /* case WLC_E_BTA_HCI_EVENT */ ++#endif /* WLBTAMP */ ++ ++ default: ++ break; ++ } ++} ++ ++void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) ++{ ++#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++ struct dhd_info *dhdinfo = dhd->info; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); ++#else ++ int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ; ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++ ++ dhd_os_sdunlock(dhd); ++ wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout); ++ dhd_os_sdlock(dhd); ++#endif ++ return; ++} ++ ++void dhd_wait_event_wakeup(dhd_pub_t *dhd) ++{ ++#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++ struct dhd_info *dhdinfo = dhd->info; ++ if (waitqueue_active(&dhdinfo->ctrl_wait)) ++ wake_up(&dhdinfo->ctrl_wait); ++#endif ++ return; ++} ++ ++int ++dhd_dev_reset(struct net_device *dev, uint8 flag) ++{ ++ int ret; ++ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ if (flag == TRUE) { ++ /* Issue wl down command before resetting the chip */ ++ if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { ++ AP6211_DEBUG("%s: wl down failed\n", __FUNCTION__); ++ } ++ } ++ ++ ret = dhd_bus_devreset(&dhd->pub, flag); ++ if (ret) { ++ AP6211_ERR("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++int net_os_set_suspend_disable(struct net_device *dev, int val) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int ret = 0; ++ ++ if (dhd) { ++ ret = dhd->pub.suspend_disable_flag; ++ dhd->pub.suspend_disable_flag = val; ++ } ++ return ret; ++} ++ ++int net_os_set_suspend(struct net_device *dev, int val, int force) ++{ ++ int ret = 0; ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ if (dhd) { ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++ ret = dhd_set_suspend(val, &dhd->pub); ++#else ++ ret = dhd_suspend_resume_helper(dhd, val, force); ++#endif ++#ifdef WL_CFG80211 ++ wl_cfg80211_update_power_mode(dev); ++#endif ++ } ++ return ret; ++} ++ ++int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ if (dhd) ++ dhd->pub.suspend_bcn_li_dtim = val; ++ ++ return 0; ++} ++ ++#ifdef PKT_FILTER_SUPPORT ++int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) ++{ ++#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ char *filterp = NULL; ++ int ret = 0; ++ ++ if (!dhd || (num == DHD_UNICAST_FILTER_NUM) || ++ (num == DHD_MDNS_FILTER_NUM)) ++ return ret; ++ if (num >= dhd->pub.pktfilter_count) ++ return -EINVAL; ++ if (add_remove) { ++ switch (num) { ++ case DHD_BROADCAST_FILTER_NUM: ++ filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF"; ++ break; ++ case DHD_MULTICAST4_FILTER_NUM: ++ filterp = "102 0 0 0 0xFFFFFF 0x01005E"; ++ break; ++ case DHD_MULTICAST6_FILTER_NUM: ++ filterp = "103 0 0 0 0xFFFF 0x3333"; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ dhd->pub.pktfilter[num] = filterp; ++ dhd_pktfilter_offload_set(&dhd->pub, dhd->pub.pktfilter[num]); ++ return ret; ++#else ++ return 0; ++#endif /* GAN_LITE_NAT_KEEPALIVE_FILTER */ ++} ++ ++int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val) ++{ ++ int ret = 0; ++ ++ /* Packet filtering is set only if we still in early-suspend and ++ * we need either to turn it ON or turn it OFF ++ * We can always turn it OFF in case of early-suspend, but we turn it ++ * back ON only if suspend_disable_flag was not set ++ */ ++ if (dhdp && dhdp->up) { ++ if (dhdp->in_suspend) { ++ if (!val || (val && !dhdp->suspend_disable_flag)) ++ dhd_enable_packet_filter(val, dhdp); ++ } ++ } ++ return ret; ++} ++ ++/* function to enable/disable packet for Network device */ ++int net_os_enable_packet_filter(struct net_device *dev, int val) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return dhd_os_enable_packet_filter(&dhd->pub, val); ++} ++#endif /* PKT_FILTER_SUPPORT */ ++ ++int ++dhd_dev_init_ioctl(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ return dhd_preinit_ioctls(&dhd->pub); ++} ++ ++#ifdef PNO_SUPPORT ++/* Linux wrapper to call common dhd_pno_clean */ ++int ++dhd_dev_pno_reset(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_pno_clean(&dhd->pub)); ++} ++ ++ ++/* Linux wrapper to call common dhd_pno_enable */ ++int ++dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_pno_enable(&dhd->pub, pfn_enabled)); ++} ++ ++ ++/* Linux wrapper to call common dhd_pno_set */ ++int ++dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, ++ ushort scan_fr, int pno_repeat, int pno_freq_expo_max) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr, pno_repeat, pno_freq_expo_max)); ++} ++ ++/* Linux wrapper to get pno status */ ++int ++dhd_dev_get_pno_status(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_pno_get_status(&dhd->pub)); ++} ++ ++#endif /* PNO_SUPPORT */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1) ++static void dhd_hang_process(struct work_struct *work) ++{ ++ dhd_info_t *dhd; ++ struct net_device *dev; ++ ++ dhd = (dhd_info_t *)container_of(work, dhd_info_t, work_hang); ++ dev = dhd->iflist[0]->net; ++ ++ if (dev) { ++ rtnl_lock(); ++ dev_close(dev); ++ rtnl_unlock(); ++#if defined(WL_WIRELESS_EXT) ++ wl_iw_send_priv_event(dev, "HANG"); ++#endif ++#if defined(WL_CFG80211) ++ wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); ++#endif ++ } ++} ++ ++int dhd_os_send_hang_message(dhd_pub_t *dhdp) ++{ ++ int ret = 0; ++ if (dhdp) { ++ if (!dhdp->hang_was_sent) { ++ dhdp->hang_was_sent = 1; ++ schedule_work(&dhdp->info->work_hang); ++ } ++ } ++ return ret; ++} ++ ++int net_os_send_hang_message(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int ret = 0; ++ ++ if (dhd) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ ret = dhd_os_send_hang_message(&dhd->pub); ++#else ++ ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); ++#endif ++ return ret; ++} ++#endif /* (OEM_ANDROID) */ ++ ++void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ if (dhd && dhd->pub.up) { ++ memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); ++#ifdef WL_CFG80211 ++ wl_update_wiphybands(NULL, true); ++#endif ++ } ++} ++ ++void dhd_bus_band_set(struct net_device *dev, uint band) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ if (dhd && dhd->pub.up) { ++#ifdef WL_CFG80211 ++ wl_update_wiphybands(NULL, true); ++#endif ++ } ++} ++ ++void dhd_net_if_lock(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ dhd_net_if_lock_local(dhd); ++} ++ ++void dhd_net_if_unlock(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ dhd_net_if_unlock_local(dhd); ++} ++ ++static void dhd_net_if_lock_local(dhd_info_t *dhd) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ if (dhd) ++ mutex_lock(&dhd->dhd_net_if_mutex); ++#endif ++} ++ ++static void dhd_net_if_unlock_local(dhd_info_t *dhd) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ if (dhd) ++ mutex_unlock(&dhd->dhd_net_if_mutex); ++#endif ++} ++ ++static void dhd_suspend_lock(dhd_pub_t *pub) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ if (dhd) ++ mutex_lock(&dhd->dhd_suspend_mutex); ++#endif ++} ++ ++static void dhd_suspend_unlock(dhd_pub_t *pub) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ if (dhd) ++ mutex_unlock(&dhd->dhd_suspend_mutex); ++#endif ++} ++ ++unsigned long dhd_os_spin_lock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags = 0; ++ ++ if (dhd) ++ spin_lock_irqsave(&dhd->dhd_lock, flags); ++ ++ return flags; ++} ++ ++void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) ++ spin_unlock_irqrestore(&dhd->dhd_lock, flags); ++} ++ ++static int ++dhd_get_pend_8021x_cnt(dhd_info_t *dhd) ++{ ++ return (atomic_read(&dhd->pend_8021x_cnt)); ++} ++ ++#define MAX_WAIT_FOR_8021X_TX 25 ++ ++int ++dhd_wait_pend8021x(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int timeout = msecs_to_jiffies(10); ++ int ntimes = MAX_WAIT_FOR_8021X_TX; ++ int pend = dhd_get_pend_8021x_cnt(dhd); ++ ++ while (ntimes && pend) { ++ if (pend) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(timeout); ++ set_current_state(TASK_RUNNING); ++ ntimes--; ++ } ++ pend = dhd_get_pend_8021x_cnt(dhd); ++ } ++ if (ntimes == 0) ++ AP6211_ERR("%s: TIMEOUT\n", __FUNCTION__); ++ return pend; ++} ++ ++#ifdef DHD_DEBUG ++int ++write_to_file(dhd_pub_t *dhd, uint8 *buf, int size) ++{ ++ int ret = 0; ++ struct file *fp; ++ mm_segment_t old_fs; ++ loff_t pos = 0; ++ ++ /* change to KERNEL_DS address limit */ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ /* open file to write */ ++ fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640); ++ if (!fp) { ++ AP6211_ERR("%s: open file error\n", __FUNCTION__); ++ ret = -1; ++ goto exit; ++ } ++ ++ /* Write buf to file */ ++ fp->f_op->write(fp, buf, size, &pos); ++ ++exit: ++ /* free buf before return */ ++ MFREE(dhd->osh, buf, size); ++ /* close file before return */ ++ if (fp) ++ filp_close(fp, current->files); ++ /* restore previous address limit */ ++ set_fs(old_fs); ++ ++ return ret; ++} ++#endif /* DHD_DEBUG */ ++ ++int dhd_os_wake_lock_timeout(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ if (dhd) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ? ++ dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable; ++#ifdef CONFIG_HAS_WAKELOCK ++ if (dhd->wakelock_rx_timeout_enable) ++ wake_lock_timeout(dhd->wl_rxwake, ++ msecs_to_jiffies(dhd->wakelock_rx_timeout_enable)); ++ if (dhd->wakelock_ctrl_timeout_enable) ++ wake_lock_timeout(dhd->wl_ctrlwake, ++ msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable)); ++#endif ++ dhd->wakelock_rx_timeout_enable = 0; ++ dhd->wakelock_ctrl_timeout_enable = 0; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return ret; ++} ++ ++int net_os_wake_lock_timeout(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int ret = 0; ++ ++ if (dhd) ++ ret = dhd_os_wake_lock_timeout(&dhd->pub); ++ return ret; ++} ++ ++int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ ++ if (dhd) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ if (val > dhd->wakelock_rx_timeout_enable) ++ dhd->wakelock_rx_timeout_enable = val; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return 0; ++} ++ ++int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ ++ if (dhd) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ if (val > dhd->wakelock_ctrl_timeout_enable) ++ dhd->wakelock_ctrl_timeout_enable = val; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return 0; ++} ++ ++int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int ret = 0; ++ ++ if (dhd) ++ ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val); ++ return ret; ++} ++ ++int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int ret = 0; ++ ++ if (dhd) ++ ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val); ++ return ret; ++} ++ ++int dhd_os_wake_lock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ if (dhd) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++#ifdef CONFIG_HAS_WAKELOCK ++ if (!dhd->wakelock_counter) ++ wake_lock(dhd->wl_wifi); ++#endif ++ dhd->wakelock_counter++; ++ ret = dhd->wakelock_counter; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return ret; ++} ++ ++int net_os_wake_lock(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int ret = 0; ++ ++ if (dhd) ++ ret = dhd_os_wake_lock(&dhd->pub); ++ return ret; ++} ++ ++int dhd_os_wake_unlock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ dhd_os_wake_lock_timeout(pub); ++ if (dhd) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ if (dhd->wakelock_counter) { ++ dhd->wakelock_counter--; ++#ifdef CONFIG_HAS_WAKELOCK ++ if (!dhd->wakelock_counter) ++ wake_unlock(dhd->wl_wifi); ++#endif ++ ret = dhd->wakelock_counter; ++ } ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return ret; ++} ++ ++int dhd_os_check_wakelock(void *dhdp) ++{ ++#ifdef CONFIG_HAS_WAKELOCK ++ dhd_pub_t *pub = (dhd_pub_t *)dhdp; ++ dhd_info_t *dhd; ++ ++ if (!pub) ++ return 0; ++ dhd = (dhd_info_t *)(pub->info); ++ ++ /* Indicate to the SD Host to avoid going to suspend if internal locks are up */ ++ if (dhd && (wake_lock_active(dhd->wl_wifi) || ++ (wake_lock_active(dhd->wl_wdwake)))) ++ return 1; ++#endif ++ return 0; ++} ++ ++int net_os_wake_unlock(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int ret = 0; ++ ++ if (dhd) ++ ret = dhd_os_wake_unlock(&dhd->pub); ++ return ret; ++} ++ ++int dhd_os_wd_wake_lock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ if (dhd) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++#ifdef CONFIG_HAS_WAKELOCK ++ /* if wakelock_wd_counter was never used : lock it at once */ ++ if (!dhd->wakelock_wd_counter) { ++ if (dhd->wl_wdwake) ++ wake_lock(dhd->wl_wdwake); ++ else { ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ return 0; ++ } ++ } ++#endif ++ dhd->wakelock_wd_counter++; ++ ret = dhd->wakelock_wd_counter; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return ret; ++} ++ ++int dhd_os_wd_wake_unlock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ if (dhd) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ if (dhd->wakelock_wd_counter) { ++ dhd->wakelock_wd_counter = 0; ++#ifdef CONFIG_HAS_WAKELOCK ++ wake_unlock(dhd->wl_wdwake); ++#endif ++ } ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return ret; ++} ++ ++int dhd_os_check_if_up(void *dhdp) ++{ ++ dhd_pub_t *pub = (dhd_pub_t *)dhdp; ++ ++ if (!pub) ++ return 0; ++ return pub->up; ++} ++ ++/* function to collect firmware, chip id and chip version info */ ++void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) ++{ ++ int i; ++ ++ i = snprintf(info_string, sizeof(info_string), "Driver: %s\n Firmware: %s ", EPI_VERSION_STR, fw); ++ ++ if (!dhdp) ++ return; ++ ++ i = snprintf(&info_string[i], sizeof(info_string) - i, ++ "\n Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp), ++ dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp)); ++ AP6211_ERR("Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp), dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp)); ++} ++ ++int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) ++{ ++ int ifidx; ++ int ret = 0; ++ dhd_info_t *dhd = NULL; ++ ++ if (!net || !netdev_priv(net)) { ++ AP6211_ERR("%s invalid parameter\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ dhd = *(dhd_info_t **)netdev_priv(net); ++ ifidx = dhd_net2idx(dhd, net); ++ if (ifidx == DHD_BAD_IF) { ++ AP6211_ERR("%s bad ifidx\n", __FUNCTION__); ++ return -ENODEV; ++ } ++ ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len); ++ dhd_check_hang(net, &dhd->pub, ret); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ ++ return ret; ++} ++ ++bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret) ++{ ++ struct net_device *net; ++ ++ net = dhd_idx2net(dhdp, ifidx); ++ return dhd_check_hang(net, dhdp, ret); ++} ++ ++ ++#ifdef PROP_TXSTATUS ++extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t action, uint8 ifid, ++ uint8 iftype, uint8* ea); ++extern int dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits); ++ ++int dhd_wlfc_interface_event(struct dhd_info *dhd, ++ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) ++{ ++ int status; ++ ++ dhd_os_wlfc_block(&dhd->pub); ++ if (dhd->pub.wlfc_state == NULL) { ++ dhd_os_wlfc_unblock(&dhd->pub); ++ return BCME_OK; ++ } ++ ++ status = dhd_wlfc_interface_entry_update(dhd->pub.wlfc_state, action, ifid, iftype, ea); ++ dhd_os_wlfc_unblock(&dhd->pub); ++ return status; ++} ++ ++int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data) ++{ ++ int status; ++ ++ dhd_os_wlfc_block(&dhd->pub); ++ if (dhd->pub.wlfc_state == NULL) { ++ dhd_os_wlfc_unblock(&dhd->pub); ++ return BCME_OK; ++ } ++ ++ status = dhd_wlfc_FIFOcreditmap_update(dhd->pub.wlfc_state, event_data); ++ dhd_os_wlfc_unblock(&dhd->pub); ++ return status; ++} ++ ++int dhd_wlfc_event(struct dhd_info *dhd) ++{ ++ int status; ++ ++ dhd_os_wlfc_block(&dhd->pub); ++ status = dhd_wlfc_enable(&dhd->pub); ++ dhd_os_wlfc_unblock(&dhd->pub); ++ return status; ++} ++#endif /* PROP_TXSTATUS */ ++ ++#ifdef BCMDBGFS ++ ++#include ++ ++extern uint32 dhd_readregl(void *bp, uint32 addr); ++extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data); ++ ++typedef struct dhd_dbgfs { ++ struct dentry *debugfs_dir; ++ struct dentry *debugfs_mem; ++ dhd_pub_t *dhdp; ++ uint32 size; ++} dhd_dbgfs_t; ++ ++dhd_dbgfs_t g_dbgfs; ++ ++static int ++dhd_dbg_state_open(struct inode *inode, struct file *file) ++{ ++ file->private_data = inode->i_private; ++ return 0; ++} ++ ++static ssize_t ++dhd_dbg_state_read(struct file *file, char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t rval; ++ uint32 tmp; ++ loff_t pos = *ppos; ++ size_t ret; ++ ++ if (pos < 0) ++ return -EINVAL; ++ if (pos >= g_dbgfs.size || !count) ++ return 0; ++ if (count > g_dbgfs.size - pos) ++ count = g_dbgfs.size - pos; ++ ++ /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */ ++ tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3)); ++ ++ ret = copy_to_user(ubuf, &tmp, 4); ++ if (ret == count) ++ return -EFAULT; ++ ++ count -= ret; ++ *ppos = pos + count; ++ rval = count; ++ ++ return rval; ++} ++ ++ ++static ssize_t ++dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) ++{ ++ loff_t pos = *ppos; ++ size_t ret; ++ uint32 buf; ++ ++ if (pos < 0) ++ return -EINVAL; ++ if (pos >= g_dbgfs.size || !count) ++ return 0; ++ if (count > g_dbgfs.size - pos) ++ count = g_dbgfs.size - pos; ++ ++ ret = copy_from_user(&buf, ubuf, sizeof(uint32)); ++ if (ret == count) ++ return -EFAULT; ++ ++ /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */ ++ dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf); ++ ++ return count; ++} ++ ++ ++loff_t ++dhd_debugfs_lseek(struct file *file, loff_t off, int whence) ++{ ++ loff_t pos = -1; ++ ++ switch (whence) { ++ case 0: ++ pos = off; ++ break; ++ case 1: ++ pos = file->f_pos + off; ++ break; ++ case 2: ++ pos = g_dbgfs.size - off; ++ } ++ return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos); ++} ++ ++static const struct file_operations dhd_dbg_state_ops = { ++ .read = dhd_dbg_state_read, ++ .write = dhd_debugfs_write, ++ .open = dhd_dbg_state_open, ++ .llseek = dhd_debugfs_lseek ++}; ++ ++static void dhd_dbg_create(void) ++{ ++ if (g_dbgfs.debugfs_dir) { ++ g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir, ++ NULL, &dhd_dbg_state_ops); ++ } ++} ++ ++void dhd_dbg_init(dhd_pub_t *dhdp) ++{ ++ int err; ++ ++ g_dbgfs.dhdp = dhdp; ++ g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */ ++ ++ g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0); ++ if (IS_ERR(g_dbgfs.debugfs_dir)) { ++ err = PTR_ERR(g_dbgfs.debugfs_dir); ++ g_dbgfs.debugfs_dir = NULL; ++ return; ++ } ++ ++ dhd_dbg_create(); ++ ++ return; ++} ++ ++void dhd_dbg_remove(void) ++{ ++ debugfs_remove(g_dbgfs.debugfs_mem); ++ debugfs_remove(g_dbgfs.debugfs_dir); ++ ++ bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs)); ++ ++} ++#endif /* ifdef BCMDBGFS */ ++ ++#ifdef WLMEDIA_HTSF ++ ++static ++void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); ++ struct sk_buff *skb; ++ uint32 htsf = 0; ++ uint16 dport = 0, oldmagic = 0xACAC; ++ char *p1; ++ htsfts_t ts; ++ ++ /* timestamp packet */ ++ ++ p1 = (char*) PKTDATA(dhdp->osh, pktbuf); ++ ++ if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) { ++/* memcpy(&proto, p1+26, 4); */ ++ memcpy(&dport, p1+40, 2); ++/* proto = ((ntoh32(proto))>> 16) & 0xFF; */ ++ dport = ntoh16(dport); ++ } ++ ++ /* timestamp only if icmp or udb iperf with port 5555 */ ++/* if (proto == 17 && dport == tsport) { */ ++ if (dport >= tsport && dport <= tsport + 20) { ++ ++ skb = (struct sk_buff *) pktbuf; ++ ++ htsf = dhd_get_htsf(dhd, 0); ++ memset(skb->data + 44, 0, 2); /* clear checksum */ ++ memcpy(skb->data+82, &oldmagic, 2); ++ memcpy(skb->data+84, &htsf, 4); ++ ++ memset(&ts, 0, sizeof(htsfts_t)); ++ ts.magic = HTSFMAGIC; ++ ts.prio = PKTPRIO(pktbuf); ++ ts.seqnum = htsf_seqnum++; ++ ts.c10 = get_cycles(); ++ ts.t10 = htsf; ++ ts.endmagic = HTSFENDMAGIC; ++ ++ memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts)); ++ } ++} ++ ++static void dhd_dump_htsfhisto(histo_t *his, char *s) ++{ ++ int pktcnt = 0, curval = 0, i; ++ for (i = 0; i < (NUMBIN-2); i++) { ++ curval += 500; ++ AP6211_DUMP("%d ", his->bin[i]); ++ pktcnt += his->bin[i]; ++ } ++ AP6211_DUMP(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt, ++ his->bin[NUMBIN-1], s); ++} ++ ++static ++void sorttobin(int value, histo_t *histo) ++{ ++ int i, binval = 0; ++ ++ if (value < 0) { ++ histo->bin[NUMBIN-1]++; ++ return; ++ } ++ if (value > histo->bin[NUMBIN-2]) /* store the max value */ ++ histo->bin[NUMBIN-2] = value; ++ ++ for (i = 0; i < (NUMBIN-2); i++) { ++ binval += 500; /* 500m s bins */ ++ if (value <= binval) { ++ histo->bin[i]++; ++ return; ++ } ++ } ++ histo->bin[NUMBIN-3]++; ++} ++ ++static ++void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ struct sk_buff *skb; ++ char *p1; ++ uint16 old_magic; ++ int d1, d2, d3, end2end; ++ htsfts_t *htsf_ts; ++ uint32 htsf; ++ ++ skb = PKTTONATIVE(dhdp->osh, pktbuf); ++ p1 = (char*)PKTDATA(dhdp->osh, pktbuf); ++ ++ if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) { ++ memcpy(&old_magic, p1+78, 2); ++ htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4); ++ } ++ else ++ return; ++ ++ if (htsf_ts->magic == HTSFMAGIC) { ++ htsf_ts->tE0 = dhd_get_htsf(dhd, 0); ++ htsf_ts->cE0 = get_cycles(); ++ } ++ ++ if (old_magic == 0xACAC) { ++ ++ tspktcnt++; ++ htsf = dhd_get_htsf(dhd, 0); ++ memcpy(skb->data+92, &htsf, sizeof(uint32)); ++ ++ memcpy(&ts[tsidx].t1, skb->data+80, 16); ++ ++ d1 = ts[tsidx].t2 - ts[tsidx].t1; ++ d2 = ts[tsidx].t3 - ts[tsidx].t2; ++ d3 = ts[tsidx].t4 - ts[tsidx].t3; ++ end2end = ts[tsidx].t4 - ts[tsidx].t1; ++ ++ sorttobin(d1, &vi_d1); ++ sorttobin(d2, &vi_d2); ++ sorttobin(d3, &vi_d3); ++ sorttobin(end2end, &vi_d4); ++ ++ if (end2end > 0 && end2end > maxdelay) { ++ maxdelay = end2end; ++ maxdelaypktno = tspktcnt; ++ memcpy(&maxdelayts, &ts[tsidx], 16); ++ } ++ if (++tsidx >= TSMAX) ++ tsidx = 0; ++ } ++} ++ ++uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx) ++{ ++ uint32 htsf = 0, cur_cycle, delta, delta_us; ++ uint32 factor, baseval, baseval2; ++ cycles_t t; ++ ++ t = get_cycles(); ++ cur_cycle = t; ++ ++ if (cur_cycle > dhd->htsf.last_cycle) ++ delta = cur_cycle - dhd->htsf.last_cycle; ++ else { ++ delta = cur_cycle + (0xFFFFFFFF - dhd->htsf.last_cycle); ++ } ++ ++ delta = delta >> 4; ++ ++ if (dhd->htsf.coef) { ++ /* times ten to get the first digit */ ++ factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1); ++ baseval = (delta*10)/factor; ++ baseval2 = (delta*10)/(factor+1); ++ delta_us = (baseval - (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10); ++ htsf = (delta_us << 4) + dhd->htsf.last_tsf + HTSF_BUS_DELAY; ++ } ++ else { ++ AP6211_ERR("-------dhd->htsf.coef = 0 -------\n"); ++ } ++ ++ return htsf; ++} ++ ++static void dhd_dump_latency(void) ++{ ++ int i, max = 0; ++ int d1, d2, d3, d4, d5; ++ ++ AP6211_DEBUG("T1 T2 T3 T4 d1 d2 t4-t1 i \n"); ++ for (i = 0; i < TSMAX; i++) { ++ d1 = ts[i].t2 - ts[i].t1; ++ d2 = ts[i].t3 - ts[i].t2; ++ d3 = ts[i].t4 - ts[i].t3; ++ d4 = ts[i].t4 - ts[i].t1; ++ d5 = ts[max].t4-ts[max].t1; ++ if (d4 > d5 && d4 > 0) { ++ max = i; ++ } ++ AP6211_DUMP("%08X %08X %08X %08X \t%d %d %d %d i=%d\n", ++ ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4, ++ d1, d2, d3, d4, i); ++ } ++ ++ AP6211_DEBUG("current idx = %d \n", tsidx); ++ ++ AP6211_DEBUG("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt); ++ AP6211_DEBUG("%08X %08X %08X %08X \t%d %d %d %d\n", ++ maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4, ++ maxdelayts.t2 - maxdelayts.t1, ++ maxdelayts.t3 - maxdelayts.t2, ++ maxdelayts.t4 - maxdelayts.t3, ++ maxdelayts.t4 - maxdelayts.t1); ++} ++ ++ ++static int ++dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx) ++{ ++ wl_ioctl_t ioc; ++ char buf[32]; ++ int ret; ++ uint32 s1, s2; ++ ++ struct tsf { ++ uint32 low; ++ uint32 high; ++ } tsf_buf; ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ memset(&tsf_buf, 0, sizeof(tsf_buf)); ++ ++ ioc.cmd = WLC_GET_VAR; ++ ioc.buf = buf; ++ ioc.len = (uint)sizeof(buf); ++ ioc.set = FALSE; ++ ++ strncpy(buf, "tsf", sizeof(buf) - 1); ++ buf[sizeof(buf) - 1] = '\0'; ++ s1 = dhd_get_htsf(dhd, 0); ++ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { ++ if (ret == -EIO) { ++ AP6211_ERR("%s: tsf is not supported by device\n", ++ dhd_ifname(&dhd->pub, ifidx)); ++ return -EOPNOTSUPP; ++ } ++ return ret; ++ } ++ s2 = dhd_get_htsf(dhd, 0); ++ ++ memcpy(&tsf_buf, buf, sizeof(tsf_buf)); ++ AP6211_DEBUG("TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ", ++ tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1, ++ dhd->htsf.coefdec2, s2-tsf_buf.low); ++ AP6211_DEBUG("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle); ++ return 0; ++} ++ ++void htsf_update(dhd_info_t *dhd, void *data) ++{ ++ static ulong cur_cycle = 0, prev_cycle = 0; ++ uint32 htsf, tsf_delta = 0; ++ uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp; ++ ulong b, a; ++ cycles_t t; ++ ++ /* cycles_t in inlcude/mips/timex.h */ ++ ++ t = get_cycles(); ++ ++ prev_cycle = cur_cycle; ++ cur_cycle = t; ++ ++ if (cur_cycle > prev_cycle) ++ cyc_delta = cur_cycle - prev_cycle; ++ else { ++ b = cur_cycle; ++ a = prev_cycle; ++ cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle); ++ } ++ ++ if (data == NULL) ++ AP6211_DEBUG(" tsf update ata point er is null \n"); ++ ++ memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t)); ++ memcpy(&cur_tsf, data, sizeof(tsf_t)); ++ ++ if (cur_tsf.low == 0) { ++ AP6211_DEBUG(" ---- 0 TSF, do not update, return\n"); ++ return; ++ } ++ ++ if (cur_tsf.low > prev_tsf.low) ++ tsf_delta = (cur_tsf.low - prev_tsf.low); ++ else { ++ AP6211_DEBUG(" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n", ++ cur_tsf.low, prev_tsf.low); ++ if (cur_tsf.high > prev_tsf.high) { ++ tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low); ++ AP6211_DEBUG(" ---- Wrap around tsf coutner adjusted TSF=%08X\n", tsf_delta); ++ } ++ else ++ return; /* do not update */ ++ } ++ ++ if (tsf_delta) { ++ hfactor = cyc_delta / tsf_delta; ++ tmp = (cyc_delta - (hfactor * tsf_delta))*10; ++ dec1 = tmp/tsf_delta; ++ dec2 = ((tmp - dec1*tsf_delta)*10) / tsf_delta; ++ tmp = (tmp - (dec1*tsf_delta))*10; ++ dec3 = ((tmp - dec2*tsf_delta)*10) / tsf_delta; ++ ++ if (dec3 > 4) { ++ if (dec2 == 9) { ++ dec2 = 0; ++ if (dec1 == 9) { ++ dec1 = 0; ++ hfactor++; ++ } ++ else { ++ dec1++; ++ } ++ } ++ else ++ dec2++; ++ } ++ } ++ ++ if (hfactor) { ++ htsf = ((cyc_delta * 10) / (hfactor*10+dec1)) + prev_tsf.low; ++ dhd->htsf.coef = hfactor; ++ dhd->htsf.last_cycle = cur_cycle; ++ dhd->htsf.last_tsf = cur_tsf.low; ++ dhd->htsf.coefdec1 = dec1; ++ dhd->htsf.coefdec2 = dec2; ++ } ++ else { ++ htsf = prev_tsf.low; ++ } ++} ++ ++#endif /* WLMEDIA_HTSF */ +diff --git a/drivers/net/wireless/ap6211/dhd_linux_sched.c b/drivers/net/wireless/ap6211/dhd_linux_sched.c +new file mode 100755 +index 0000000..290caf7 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_linux_sched.c +@@ -0,0 +1,39 @@ ++/* ++ * Expose some of the kernel scheduler routines ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_linux_sched.c 291086 2011-10-21 01:17:24Z $ ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++int setScheduler(struct task_struct *p, int policy, struct sched_param *param) ++{ ++ int rc = 0; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++ rc = sched_setscheduler(p, policy, param); ++#endif /* LinuxVer */ ++ return rc; ++} +diff --git a/drivers/net/wireless/ap6211/dhd_pno.c b/drivers/net/wireless/ap6211/dhd_pno.c +new file mode 100755 +index 0000000..317a063 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_pno.c +@@ -0,0 +1,1838 @@ ++/* ++ * Broadcom Dongle Host Driver (DHD) ++ * Prefered Network Offload and Wi-Fi Location Service(WLS) code. ++ * ++ * Copyright (C) 1999-2013, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_pno.c 420056 2013-08-24 00:53:12Z $ ++ */ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#ifdef __BIG_ENDIAN ++#include ++#define htod32(i) (bcmswap32(i)) ++#define htod16(i) (bcmswap16(i)) ++#define dtoh32(i) (bcmswap32(i)) ++#define dtoh16(i) (bcmswap16(i)) ++#define htodchanspec(i) htod16(i) ++#define dtohchanspec(i) dtoh16(i) ++#else ++#define htod32(i) i ++#define htod16(i) i ++#define dtoh32(i) i ++#define dtoh16(i) i ++#define htodchanspec(i) i ++#define dtohchanspec(i) i ++#endif /* IL_BIGENDINA */ ++ ++#define NULL_CHECK(p, s, err) \ ++ do { \ ++ if (!(p)) { \ ++ printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ ++ err = BCME_ERROR; \ ++ return err; \ ++ } \ ++ } while (0) ++#define PNO_GET_PNOSTATE(dhd) ((dhd_pno_status_info_t *)dhd->pno_state) ++#define PNO_BESTNET_LEN 1024 ++#define PNO_ON 1 ++#define PNO_OFF 0 ++#define CHANNEL_2G_MAX 14 ++#define MAX_NODE_CNT 5 ++#define WLS_SUPPORTED(pno_state) (pno_state->wls_supported == TRUE) ++#define TIME_DIFF(timestamp1, timestamp2) (abs((uint32)(timestamp1/1000) \ ++ - (uint32)(timestamp2/1000))) ++ ++#define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====") ++#define TIME_MIN_DIFF 5 ++static inline bool ++is_dfs(uint16 channel) ++{ ++ if (channel >= 52 && channel <= 64) /* class 2 */ ++ return TRUE; ++ else if (channel >= 100 && channel <= 140) /* class 4 */ ++ return TRUE; ++ else ++ return FALSE; ++} ++static int ++_dhd_pno_clean(dhd_pub_t *dhd) ++{ ++ int pfn = 0; ++ int err; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ /* Disable PNO */ ++ err = dhd_iovar(dhd, 0, "pfn", (char *)&pfn, sizeof(pfn), 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to execute pfn(error : %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ _pno_state->pno_status = DHD_PNO_DISABLED; ++ err = dhd_iovar(dhd, 0, "pfnclear", NULL, 0, 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to execute pfnclear(error : %d)\n", ++ __FUNCTION__, err); ++ } ++exit: ++ return err; ++} ++ ++static int ++_dhd_pno_suspend(dhd_pub_t *dhd) ++{ ++ int err; ++ int suspend = 1; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ err = dhd_iovar(dhd, 0, "pfn_suspend", (char *)&suspend, sizeof(suspend), 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to suspend pfn(error :%d)\n", __FUNCTION__, err); ++ goto exit; ++ ++ } ++ _pno_state->pno_status = DHD_PNO_SUSPEND; ++exit: ++ return err; ++} ++static int ++_dhd_pno_enable(dhd_pub_t *dhd, int enable) ++{ ++ int err = BCME_OK; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ ++ if (enable & 0xfffe) { ++ AP6211_ERR("%s invalid value\n", __FUNCTION__); ++ err = BCME_BADARG; ++ goto exit; ++ } ++ if (!dhd_support_sta_mode(dhd)) { ++ AP6211_ERR("PNO is not allowed for non-STA mode"); ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ if (enable) { ++ if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) && ++ dhd_is_associated(dhd, NULL, NULL)) { ++ AP6211_ERR("%s Legacy PNO mode cannot be enabled " ++ "in assoc mode , ignore it\n", __FUNCTION__); ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ } ++ /* Enable/Disable PNO */ ++ err = dhd_iovar(dhd, 0, "pfn", (char *)&enable, sizeof(enable), 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to execute pfn_set\n", __FUNCTION__); ++ goto exit; ++ } ++ _pno_state->pno_status = (enable)? ++ DHD_PNO_ENABLED : DHD_PNO_DISABLED; ++ if (!enable) ++ _pno_state->pno_mode = DHD_PNO_NONE_MODE; ++ ++ AP6211_DEBUG("%s set pno as %s\n", ++ __FUNCTION__, enable ? "Enable" : "Disable"); ++exit: ++ return err; ++} ++ ++static int ++_dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t mode) ++{ ++ int err = BCME_OK; ++ wl_pfn_param_t pfn_param; ++ dhd_pno_params_t *_params; ++ dhd_pno_status_info_t *_pno_state; ++ bool combined_scan = FALSE; ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ ++ memset(&pfn_param, 0, sizeof(pfn_param)); ++ ++ /* set pfn parameters */ ++ pfn_param.version = htod32(PFN_VERSION); ++ pfn_param.flags = ((PFN_LIST_ORDER << SORT_CRITERIA_BIT) | ++ (ENABLE << IMMEDIATE_SCAN_BIT) | (ENABLE << REPORT_SEPERATELY_BIT)); ++ if (mode == DHD_PNO_LEGACY_MODE) { ++ /* check and set extra pno params */ ++ if ((pno_params->params_legacy.pno_repeat != 0) || ++ (pno_params->params_legacy.pno_freq_expo_max != 0)) { ++ pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); ++ pfn_param.repeat = (uchar) (pno_params->params_legacy.pno_repeat); ++ pfn_param.exp = (uchar) (pno_params->params_legacy.pno_freq_expo_max); ++ } ++ /* set up pno scan fr */ ++ if (pno_params->params_legacy.scan_fr != 0) ++ pfn_param.scan_freq = htod32(pno_params->params_legacy.scan_fr); ++ if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ AP6211_DEBUG("will enable combined scan with BATCHIG SCAN MODE\n"); ++ mode |= DHD_PNO_BATCH_MODE; ++ combined_scan = TRUE; ++ } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { ++ AP6211_DEBUG("will enable combined scan with HOTLIST SCAN MODE\n"); ++ mode |= DHD_PNO_HOTLIST_MODE; ++ combined_scan = TRUE; ++ } ++ } ++ if (mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { ++ /* Scan frequency of 30 sec */ ++ pfn_param.scan_freq = htod32(30); ++ /* slow adapt scan is off by default */ ++ pfn_param.slow_freq = htod32(0); ++ /* RSSI margin of 30 dBm */ ++ pfn_param.rssi_margin = htod16(30); ++ /* Network timeout 60 sec */ ++ pfn_param.lost_network_timeout = htod32(60); ++ /* best n = 2 by default */ ++ pfn_param.bestn = DEFAULT_BESTN; ++ /* mscan m=0 by default, so not record best networks by default */ ++ pfn_param.mscan = DEFAULT_MSCAN; ++ /* default repeat = 10 */ ++ pfn_param.repeat = DEFAULT_REPEAT; ++ /* by default, maximum scan interval = 2^2 ++ * scan_freq when adaptive scan is turned on ++ */ ++ pfn_param.exp = DEFAULT_EXP; ++ if (mode == DHD_PNO_BATCH_MODE) { ++ /* In case of BATCH SCAN */ ++ if (pno_params->params_batch.bestn) ++ pfn_param.bestn = pno_params->params_batch.bestn; ++ if (pno_params->params_batch.scan_fr) ++ pfn_param.scan_freq = htod32(pno_params->params_batch.scan_fr); ++ if (pno_params->params_batch.mscan) ++ pfn_param.mscan = pno_params->params_batch.mscan; ++ /* enable broadcast scan */ ++ pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); ++ } else if (mode == DHD_PNO_HOTLIST_MODE) { ++ /* In case of HOTLIST SCAN */ ++ if (pno_params->params_hotlist.scan_fr) ++ pfn_param.scan_freq = htod32(pno_params->params_hotlist.scan_fr); ++ pfn_param.bestn = 0; ++ pfn_param.repeat = 0; ++ /* enable broadcast scan */ ++ pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); ++ } ++ if (combined_scan) { ++ /* Disable Adaptive Scan */ ++ pfn_param.flags &= ~(htod16(ENABLE << ENABLE_ADAPTSCAN_BIT)); ++ pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); ++ pfn_param.repeat = 0; ++ pfn_param.exp = 0; ++ if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ /* In case of Legacy PNO + BATCH SCAN */ ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); ++ if (_params->params_batch.bestn) ++ pfn_param.bestn = _params->params_batch.bestn; ++ if (_params->params_batch.scan_fr) ++ pfn_param.scan_freq = htod32(_params->params_batch.scan_fr); ++ if (_params->params_batch.mscan) ++ pfn_param.mscan = _params->params_batch.mscan; ++ } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { ++ /* In case of Legacy PNO + HOTLIST SCAN */ ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); ++ if (_params->params_hotlist.scan_fr) ++ pfn_param.scan_freq = htod32(_params->params_hotlist.scan_fr); ++ pfn_param.bestn = 0; ++ pfn_param.repeat = 0; ++ } ++ } ++ } ++ if (pfn_param.scan_freq < htod32(PNO_SCAN_MIN_FW_SEC) || ++ pfn_param.scan_freq > htod32(PNO_SCAN_MAX_FW_SEC)) { ++ AP6211_ERR("%s pno freq(%d sec) is not valid \n", ++ __FUNCTION__, PNO_SCAN_MIN_FW_SEC); ++ err = BCME_BADARG; ++ goto exit; ++ } ++ if (mode == DHD_PNO_BATCH_MODE) { ++ int _tmp = pfn_param.bestn; ++ /* set bestn to calculate the max mscan which firmware supports */ ++ err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to set pfnmscan\n", __FUNCTION__); ++ goto exit; ++ } ++ /* get max mscan which the firmware supports */ ++ err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), 0); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to get pfnmscan\n", __FUNCTION__); ++ goto exit; ++ } ++ AP6211_DEBUG(" returned mscan : %d, set bestn : %d\n", _tmp, pfn_param.bestn); ++ pfn_param.mscan = MIN(pfn_param.mscan, _tmp); ++ } ++ err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to execute pfn_set\n", __FUNCTION__); ++ goto exit; ++ } ++ /* need to return mscan if this is for batch scan instead of err */ ++ err = (mode == DHD_PNO_BATCH_MODE)? pfn_param.mscan : err; ++exit: ++ return err; ++} ++static int ++_dhd_pno_add_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssids_list, int nssid) ++{ ++ int err = BCME_OK; ++ int i = 0; ++ wl_pfn_t pfn_element; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ if (nssid) { ++ NULL_CHECK(ssids_list, "ssid list is NULL", err); ++ } ++ memset(&pfn_element, 0, sizeof(pfn_element)); ++ { ++ int j; ++ for (j = 0; j < nssid; j++) { ++ AP6211_DEBUG("%d: scan for %s size = %d\n", j, ++ ssids_list[j].SSID, ssids_list[j].SSID_len); ++ } ++ } ++ /* Check for broadcast ssid */ ++ for (i = 0; i < nssid; i++) { ++ if (!ssids_list[i].SSID_len) { ++ AP6211_ERR("%d: Broadcast SSID is ilegal for PNO setting\n", i); ++ err = BCME_ERROR; ++ goto exit; ++ } ++ } ++ /* set all pfn ssid */ ++ for (i = 0; i < nssid; i++) { ++ pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); ++ pfn_element.auth = (DOT11_OPEN_SYSTEM); ++ pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); ++ pfn_element.wsec = htod32(0); ++ pfn_element.infra = htod32(1); ++ pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT); ++ memcpy((char *)pfn_element.ssid.SSID, ssids_list[i].SSID, ++ ssids_list[i].SSID_len); ++ pfn_element.ssid.SSID_len = ssids_list[i].SSID_len; ++ err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_element, ++ sizeof(pfn_element), 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to execute pfn_add\n", __FUNCTION__); ++ goto exit; ++ } ++ } ++exit: ++ return err; ++} ++/* qsort compare function */ ++static int ++_dhd_pno_cmpfunc(const void *a, const void *b) ++{ ++ return (*(uint16*)a - *(uint16*)b); ++} ++static int ++_dhd_pno_chan_merge(uint16 *d_chan_list, int *nchan, ++ uint16 *chan_list1, int nchan1, uint16 *chan_list2, int nchan2) ++{ ++ int err = BCME_OK; ++ int i = 0, j = 0, k = 0; ++ uint16 tmp; ++ NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); ++ NULL_CHECK(nchan, "nchan is NULL", err); ++ NULL_CHECK(chan_list1, "chan_list1 is NULL", err); ++ NULL_CHECK(chan_list2, "chan_list2 is NULL", err); ++ /* chan_list1 and chan_list2 should be sorted at first */ ++ while (i < nchan1 && j < nchan2) { ++ tmp = chan_list1[i] < chan_list2[j]? ++ chan_list1[i++] : chan_list2[j++]; ++ for (; i < nchan1 && chan_list1[i] == tmp; i++); ++ for (; j < nchan2 && chan_list2[j] == tmp; j++); ++ d_chan_list[k++] = tmp; ++ } ++ ++ while (i < nchan1) { ++ tmp = chan_list1[i++]; ++ for (; i < nchan1 && chan_list1[i] == tmp; i++); ++ d_chan_list[k++] = tmp; ++ } ++ ++ while (j < nchan2) { ++ tmp = chan_list2[j++]; ++ for (; j < nchan2 && chan_list2[j] == tmp; j++); ++ d_chan_list[k++] = tmp; ++ ++ } ++ *nchan = k; ++ return err; ++} ++static int ++_dhd_pno_get_channels(dhd_pub_t *dhd, uint16 *d_chan_list, ++ int *nchan, uint8 band, bool skip_dfs) ++{ ++ int err = BCME_OK; ++ int i, j; ++ uint32 chan_buf[WL_NUMCHANNELS + 1]; ++ wl_uint32_list_t *list; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ if (*nchan) { ++ NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); ++ } ++ list = (wl_uint32_list_t *) (void *)chan_buf; ++ list->count = htod32(WL_NUMCHANNELS); ++ err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, chan_buf, sizeof(chan_buf), FALSE, 0); ++ if (err < 0) { ++ AP6211_ERR("failed to get channel list (err: %d)\n", err); ++ goto exit; ++ } ++ for (i = 0, j = 0; i < dtoh32(list->count) && i < *nchan; i++) { ++ if (band == WLC_BAND_2G) { ++ if (dtoh32(list->element[i]) > CHANNEL_2G_MAX) ++ continue; ++ } else if (band == WLC_BAND_5G) { ++ if (dtoh32(list->element[i]) <= CHANNEL_2G_MAX) ++ continue; ++ if (skip_dfs && is_dfs(dtoh32(list->element[i]))) ++ continue; ++ ++ } else { /* All channels */ ++ if (skip_dfs && is_dfs(dtoh32(list->element[i]))) ++ continue; ++ } ++ d_chan_list[j++] = dtoh32(list->element[i]); ++ } ++ *nchan = j; ++exit: ++ return err; ++} ++static int ++_dhd_pno_convert_format(dhd_pub_t *dhd, struct dhd_pno_batch_params *params_batch, ++ char *buf, int nbufsize) ++{ ++ int err = BCME_OK; ++ int bytes_written = 0, nreadsize = 0; ++ int t_delta = 0; ++ int nleftsize = nbufsize; ++ uint8 cnt = 0; ++ char *bp = buf; ++ char eabuf[ETHER_ADDR_STR_LEN]; ++#ifdef PNO_DEBUG ++ char *_base_bp; ++ char msg[150]; ++#endif ++ dhd_pno_bestnet_entry_t *iter, *next; ++ dhd_pno_scan_results_t *siter, *snext; ++ dhd_pno_best_header_t *phead, *pprev; ++ NULL_CHECK(params_batch, "params_batch is NULL", err); ++ if (nbufsize > 0) ++ NULL_CHECK(buf, "buf is NULL", err); ++ /* initialize the buffer */ ++ memset(buf, 0, nbufsize); ++ AP6211_DEBUG("%s enter \n", __FUNCTION__); ++ /* # of scans */ ++ if (!params_batch->get_batch.batch_started) { ++ bp += nreadsize = sprintf(bp, "scancount=%d\n", ++ params_batch->get_batch.expired_tot_scan_cnt); ++ nleftsize -= nreadsize; ++ params_batch->get_batch.batch_started = TRUE; ++ } ++ AP6211_DEBUG("%s scancount %d\n", __FUNCTION__, params_batch->get_batch.expired_tot_scan_cnt); ++ /* preestimate scan count until which scan result this report is going to end */ ++ list_for_each_entry_safe(siter, snext, ++ ¶ms_batch->get_batch.expired_scan_results_list, list) { ++ phead = siter->bestnetheader; ++ while (phead != NULL) { ++ /* if left_size is less than bestheader total size , stop this */ ++ if (nleftsize <= ++ (phead->tot_size + phead->tot_cnt * ENTRY_OVERHEAD)) ++ goto exit; ++ /* increase scan count */ ++ cnt++; ++ /* # best of each scan */ ++ AP6211_DEBUG("\n", cnt - 1, phead->tot_cnt); ++ /* attribute of the scan */ ++ if (phead->reason & PNO_STATUS_ABORT_MASK) { ++ bp += nreadsize = sprintf(bp, "trunc\n"); ++ nleftsize -= nreadsize; ++ } ++ list_for_each_entry_safe(iter, next, ++ &phead->entry_list, list) { ++ t_delta = jiffies_to_msecs(jiffies - iter->recorded_time); ++#ifdef PNO_DEBUG ++ _base_bp = bp; ++ memset(msg, 0, sizeof(msg)); ++#endif ++ /* BSSID info */ ++ bp += nreadsize = sprintf(bp, "bssid=%s\n", ++ bcm_ether_ntoa((const struct ether_addr *)&iter->BSSID, eabuf)); ++ nleftsize -= nreadsize; ++ /* SSID */ ++ bp += nreadsize = sprintf(bp, "ssid=%s\n", iter->SSID); ++ nleftsize -= nreadsize; ++ /* channel */ ++ bp += nreadsize = sprintf(bp, "freq=%d\n", ++ wf_channel2mhz(iter->channel, ++ iter->channel <= CH_MAX_2G_CHANNEL? ++ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); ++ nleftsize -= nreadsize; ++ /* RSSI */ ++ bp += nreadsize = sprintf(bp, "level=%d\n", iter->RSSI); ++ nleftsize -= nreadsize; ++ /* add the time consumed in Driver to the timestamp of firmware */ ++ iter->timestamp += t_delta; ++ bp += nreadsize = sprintf(bp, "age=%d\n", iter->timestamp); ++ nleftsize -= nreadsize; ++ /* RTT0 */ ++ bp += nreadsize = sprintf(bp, "dist=%d\n", ++ (iter->rtt0 == 0)? -1 : iter->rtt0); ++ nleftsize -= nreadsize; ++ /* RTT1 */ ++ bp += nreadsize = sprintf(bp, "distSd=%d\n", ++ (iter->rtt0 == 0)? -1 : iter->rtt1); ++ nleftsize -= nreadsize; ++ bp += nreadsize = sprintf(bp, "%s", AP_END_MARKER); ++ nleftsize -= nreadsize; ++ list_del(&iter->list); ++ MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); ++#ifdef PNO_DEBUG ++ memcpy(msg, _base_bp, bp - _base_bp); ++ AP6211_DEBUG("Entry : \n%s", msg); ++#endif ++ } ++ bp += nreadsize = sprintf(bp, "%s", SCAN_END_MARKER); ++ AP6211_DEBUG("%s", SCAN_END_MARKER); ++ nleftsize -= nreadsize; ++ pprev = phead; ++ /* reset the header */ ++ siter->bestnetheader = phead = phead->next; ++ MFREE(dhd->osh, pprev, BEST_HEADER_SIZE); ++ ++ siter->cnt_header--; ++ } ++ if (phead == NULL) { ++ /* we store all entry in this scan , so it is ok to delete */ ++ list_del(&siter->list); ++ MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); ++ } ++ } ++exit: ++ if (cnt < params_batch->get_batch.expired_tot_scan_cnt) { ++ AP6211_ERR("Buffer size is small to save all batch entry," ++ " cnt : %d (remained_scan_cnt): %d\n", ++ cnt, params_batch->get_batch.expired_tot_scan_cnt - cnt); ++ } ++ params_batch->get_batch.expired_tot_scan_cnt -= cnt; ++ /* set FALSE only if the link list is empty after returning the data */ ++ if (list_empty(¶ms_batch->get_batch.expired_scan_results_list)) { ++ params_batch->get_batch.batch_started = FALSE; ++ bp += sprintf(bp, "%s", RESULTS_END_MARKER); ++ AP6211_DEBUG("%s", RESULTS_END_MARKER); ++ AP6211_DEBUG("%s : Getting the batching data is complete\n", __FUNCTION__); ++ } ++ /* return used memory in buffer */ ++ bytes_written = (int32)(bp - buf); ++ return bytes_written; ++} ++static int ++_dhd_pno_clear_all_batch_results(dhd_pub_t *dhd, struct list_head *head, bool only_last) ++{ ++ int err = BCME_OK; ++ int removed_scan_cnt = 0; ++ dhd_pno_scan_results_t *siter, *snext; ++ dhd_pno_best_header_t *phead, *pprev; ++ dhd_pno_bestnet_entry_t *iter, *next; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(head, "head is NULL", err); ++ NULL_CHECK(head->next, "head->next is NULL", err); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ list_for_each_entry_safe(siter, snext, ++ head, list) { ++ if (only_last) { ++ /* in case that we need to delete only last one */ ++ if (!list_is_last(&siter->list, head)) { ++ /* skip if the one is not last */ ++ continue; ++ } ++ } ++ /* delete all data belong if the one is last */ ++ phead = siter->bestnetheader; ++ while (phead != NULL) { ++ removed_scan_cnt++; ++ list_for_each_entry_safe(iter, next, ++ &phead->entry_list, list) { ++ list_del(&iter->list); ++ MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); ++ } ++ pprev = phead; ++ phead = phead->next; ++ MFREE(dhd->osh, pprev, BEST_HEADER_SIZE); ++ } ++ if (phead == NULL) { ++ /* it is ok to delete top node */ ++ list_del(&siter->list); ++ MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); ++ } ++ } ++ return removed_scan_cnt; ++} ++ ++static int ++_dhd_pno_cfg(dhd_pub_t *dhd, uint16 *channel_list, int nchan) ++{ ++ int err = BCME_OK; ++ int i = 0; ++ wl_pfn_cfg_t pfncfg_param; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ if (nchan) { ++ NULL_CHECK(channel_list, "nchan is NULL", err); ++ } ++ AP6211_DEBUG("%s enter : nchan : %d\n", __FUNCTION__, nchan); ++ memset(&pfncfg_param, 0, sizeof(wl_pfn_cfg_t)); ++ /* Setup default values */ ++ pfncfg_param.reporttype = htod32(WL_PFN_REPORT_ALLNET); ++ pfncfg_param.channel_num = htod32(0); ++ ++ for (i = 0; i < nchan && nchan < WL_NUMCHANNELS; i++) ++ pfncfg_param.channel_list[i] = channel_list[i]; ++ ++ pfncfg_param.channel_num = htod32(nchan); ++ err = dhd_iovar(dhd, 0, "pfn_cfg", (char *)&pfncfg_param, sizeof(pfncfg_param), 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to execute pfn_cfg\n", __FUNCTION__); ++ goto exit; ++ } ++exit: ++ return err; ++} ++static int ++_dhd_pno_reinitialize_prof(dhd_pub_t *dhd, dhd_pno_params_t *params, dhd_pno_mode_t mode) ++{ ++ int err = BCME_OK; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL\n", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL\n", err); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ mutex_lock(&_pno_state->pno_mutex); ++ switch (mode) { ++ case DHD_PNO_LEGACY_MODE: { ++ struct dhd_pno_ssid *iter, *next; ++ if (params->params_legacy.nssid > 0) { ++ list_for_each_entry_safe(iter, next, ++ ¶ms->params_legacy.ssid_list, list) { ++ list_del(&iter->list); ++ kfree(iter); ++ } ++ } ++ params->params_legacy.scan_fr = 0; ++ params->params_legacy.pno_freq_expo_max = 0; ++ params->params_legacy.pno_repeat = 0; ++ params->params_legacy.nchan = 0; ++ memset(params->params_legacy.chan_list, 0, ++ sizeof(params->params_legacy.chan_list)); ++ break; ++ } ++ case DHD_PNO_BATCH_MODE: { ++ params->params_batch.scan_fr = 0; ++ params->params_batch.mscan = 0; ++ params->params_batch.nchan = 0; ++ params->params_batch.rtt = 0; ++ params->params_batch.bestn = 0; ++ params->params_batch.nchan = 0; ++ params->params_batch.band = WLC_BAND_AUTO; ++ memset(params->params_batch.chan_list, 0, ++ sizeof(params->params_batch.chan_list)); ++ params->params_batch.get_batch.batch_started = FALSE; ++ params->params_batch.get_batch.buf = NULL; ++ params->params_batch.get_batch.bufsize = 0; ++ params->params_batch.get_batch.reason = 0; ++ _dhd_pno_clear_all_batch_results(dhd, ++ ¶ms->params_batch.get_batch.scan_results_list, FALSE); ++ _dhd_pno_clear_all_batch_results(dhd, ++ ¶ms->params_batch.get_batch.expired_scan_results_list, FALSE); ++ params->params_batch.get_batch.tot_scan_cnt = 0; ++ params->params_batch.get_batch.expired_tot_scan_cnt = 0; ++ params->params_batch.get_batch.top_node_cnt = 0; ++ INIT_LIST_HEAD(¶ms->params_batch.get_batch.scan_results_list); ++ INIT_LIST_HEAD(¶ms->params_batch.get_batch.expired_scan_results_list); ++ break; ++ } ++ case DHD_PNO_HOTLIST_MODE: { ++ struct dhd_pno_bssid *iter, *next; ++ if (params->params_hotlist.nbssid > 0) { ++ list_for_each_entry_safe(iter, next, ++ ¶ms->params_hotlist.bssid_list, list) { ++ list_del(&iter->list); ++ kfree(iter); ++ } ++ } ++ params->params_hotlist.scan_fr = 0; ++ params->params_hotlist.nbssid = 0; ++ params->params_hotlist.nchan = 0; ++ params->params_batch.band = WLC_BAND_AUTO; ++ memset(params->params_hotlist.chan_list, 0, ++ sizeof(params->params_hotlist.chan_list)); ++ break; ++ } ++ default: ++ AP6211_ERR("%s : unknown mode : %d\n", __FUNCTION__, mode); ++ break; ++ } ++ mutex_unlock(&_pno_state->pno_mutex); ++ return err; ++} ++static int ++_dhd_pno_add_bssid(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, int nbssid) ++{ ++ int err = BCME_OK; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ if (nbssid) { ++ NULL_CHECK(p_pfn_bssid, "bssid list is NULL", err); ++ } ++ err = dhd_iovar(dhd, 0, "pfn_add_bssid", (char *)&p_pfn_bssid, ++ sizeof(wl_pfn_bssid_t) * nbssid, 1); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to execute pfn_cfg\n", __FUNCTION__); ++ goto exit; ++ } ++exit: ++ return err; ++} ++int ++dhd_pno_stop_for_ssid(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ uint32 mode = 0; ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pno_params_t *_params; ++ wl_pfn_bssid_t *p_pfn_bssid; ++ NULL_CHECK(dhd, "dev is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ if (!(_pno_state->pno_mode & DHD_PNO_LEGACY_MODE)) { ++ AP6211_ERR("%s : LEGACY PNO MODE is not enabled\n", __FUNCTION__); ++ goto exit; ++ } ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++ /* restart Batch mode if the batch mode is on */ ++ if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { ++ /* retrieve the batching data from firmware into host */ ++ dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); ++ /* save current pno_mode before calling dhd_pno_clean */ ++ mode = _pno_state->pno_mode; ++ _dhd_pno_clean(dhd); ++ /* restore previous pno_mode */ ++ _pno_state->pno_mode = mode; ++ if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); ++ /* restart BATCH SCAN */ ++ err = dhd_pno_set_for_batch(dhd, &_params->params_batch); ++ if (err < 0) { ++ _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; ++ AP6211_ERR("%s : failed to restart batch scan(err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { ++ /* restart HOTLIST SCAN */ ++ struct dhd_pno_bssid *iter, *next; ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); ++ p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * ++ _params->params_hotlist.nbssid, GFP_KERNEL); ++ if (p_pfn_bssid == NULL) { ++ AP6211_ERR("%s : failed to allocate wl_pfn_bssid_t array" ++ " (count: %d)", ++ __FUNCTION__, _params->params_hotlist.nbssid); ++ err = BCME_ERROR; ++ _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; ++ goto exit; ++ } ++ /* convert dhd_pno_bssid to wl_pfn_bssid */ ++ list_for_each_entry_safe(iter, next, ++ &_params->params_hotlist.bssid_list, list) { ++ memcpy(&p_pfn_bssid->macaddr, ++ &iter->macaddr, ETHER_ADDR_LEN); ++ p_pfn_bssid->flags = iter->flags; ++ p_pfn_bssid++; ++ } ++ err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); ++ if (err < 0) { ++ _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; ++ AP6211_ERR("%s : failed to restart hotlist scan(err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++ } else { ++ err = _dhd_pno_clean(dhd); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to call _dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++exit: ++ return err; ++} ++ ++int ++dhd_pno_enable(dhd_pub_t *dhd, int enable) ++{ ++ int err = BCME_OK; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ return (_dhd_pno_enable(dhd, enable)); ++} ++ ++int ++dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssid_list, int nssid, ++ uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan) ++{ ++ struct dhd_pno_ssid *_pno_ssid; ++ dhd_pno_params_t *_params; ++ dhd_pno_params_t *_params2; ++ dhd_pno_status_info_t *_pno_state; ++ uint16 _chan_list[WL_NUMCHANNELS]; ++ int32 tot_nchan = 0; ++ int err = BCME_OK; ++ int i; ++ int mode = 0; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ AP6211_DEBUG("%s enter : scan_fr :%d, pno_repeat :%d," ++ "pno_freq_expo_max: %d, nchan :%d\n", __FUNCTION__, ++ scan_fr, pno_repeat, pno_freq_expo_max, nchan); ++ ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); ++ if (!(_pno_state->pno_mode & DHD_PNO_LEGACY_MODE)) { ++ _pno_state->pno_mode |= DHD_PNO_LEGACY_MODE; ++ err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to reinitialize profile (err %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++ memset(_chan_list, 0, sizeof(_chan_list)); ++ tot_nchan = nchan; ++ if (tot_nchan > 0 && channel_list) { ++ for (i = 0; i < nchan; i++) ++ _params->params_legacy.chan_list[i] = _chan_list[i] = channel_list[i]; ++ } ++ if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { ++ AP6211_DEBUG("BATCH SCAN is on progress in firmware\n"); ++ /* retrieve the batching data from firmware into host */ ++ dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); ++ /* store current pno_mode before disabling pno */ ++ mode = _pno_state->pno_mode; ++ err = _dhd_pno_enable(dhd, PNO_OFF); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to disable PNO\n", __FUNCTION__); ++ goto exit; ++ } ++ /* restore the previous mode */ ++ _pno_state->pno_mode = mode; ++ /* use superset of channel list between two mode */ ++ if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ _params2 = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); ++ if (_params2->params_batch.nchan > 0 && nchan > 0) { ++ err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, ++ &_params2->params_batch.chan_list[0], ++ _params2->params_batch.nchan, ++ &channel_list[0], nchan); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to merge channel list" ++ " between legacy and batch\n", ++ __FUNCTION__); ++ goto exit; ++ } ++ } else { ++ AP6211_DEBUG("superset channel will use" ++ " all channels in firmware\n"); ++ } ++ } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { ++ _params2 = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); ++ if (_params2->params_hotlist.nchan > 0 && nchan > 0) { ++ err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, ++ &_params2->params_hotlist.chan_list[0], ++ _params2->params_hotlist.nchan, ++ &channel_list[0], nchan); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to merge channel list" ++ " between legacy and hotlist\n", ++ __FUNCTION__); ++ goto exit; ++ } ++ } ++ } ++ } ++ _params->params_legacy.scan_fr = scan_fr; ++ _params->params_legacy.pno_repeat = pno_repeat; ++ _params->params_legacy.pno_freq_expo_max = pno_freq_expo_max; ++ _params->params_legacy.nchan = nchan; ++ _params->params_legacy.nssid = nssid; ++ INIT_LIST_HEAD(&_params->params_legacy.ssid_list); ++ if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_LEGACY_MODE)) < 0) { ++ AP6211_ERR("failed to set call pno_set (err %d) in firmware\n", err); ++ goto exit; ++ } ++ if ((err = _dhd_pno_add_ssid(dhd, ssid_list, nssid)) < 0) { ++ AP6211_ERR("failed to add ssid list (err %d) in firmware\n", err); ++ goto exit; ++ } ++ for (i = 0; i < nssid; i++) { ++ _pno_ssid = kzalloc(sizeof(struct dhd_pno_ssid), GFP_KERNEL); ++ if (_pno_ssid == NULL) { ++ AP6211_ERR("%s : failed to allocate struct dhd_pno_ssid\n", ++ __FUNCTION__); ++ goto exit; ++ } ++ _pno_ssid->SSID_len = ssid_list[i].SSID_len; ++ memcpy(_pno_ssid->SSID, ssid_list[i].SSID, _pno_ssid->SSID_len); ++ list_add_tail(&_pno_ssid->list, &_params->params_legacy.ssid_list); ++ ++ } ++ if (tot_nchan > 0) { ++ if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { ++ AP6211_ERR("%s : failed to set call pno_cfg (err %d) in firmware\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++ if (_pno_state->pno_status == DHD_PNO_DISABLED) { ++ if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) ++ AP6211_ERR("%s : failed to enable PNO\n", __FUNCTION__); ++ } ++exit: ++ /* clear mode in case of error */ ++ if (err < 0) ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++ return err; ++} ++int ++dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params) ++{ ++ int err = BCME_OK; ++ uint16 _chan_list[WL_NUMCHANNELS]; ++ int rem_nchan = 0, tot_nchan = 0; ++ int mode = 0, mscan = 0; ++ int i = 0; ++ dhd_pno_params_t *_params; ++ dhd_pno_params_t *_params2; ++ dhd_pno_status_info_t *_pno_state; ++ wlc_ssid_t *p_ssid_list = NULL; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ NULL_CHECK(batch_params, "batch_params is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ if (!WLS_SUPPORTED(_pno_state)) { ++ AP6211_ERR("%s : wifi location service is not supported\n", __FUNCTION__); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; ++ if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { ++ _pno_state->pno_mode |= DHD_PNO_BATCH_MODE; ++ err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to call _dhd_pno_reinitialize_prof\n", ++ __FUNCTION__); ++ goto exit; ++ } ++ } ++ _params->params_batch.scan_fr = batch_params->scan_fr; ++ _params->params_batch.bestn = batch_params->bestn; ++ _params->params_batch.mscan = (batch_params->mscan)? ++ batch_params->mscan : DEFAULT_BATCH_MSCAN; ++ _params->params_batch.nchan = batch_params->nchan; ++ memcpy(_params->params_batch.chan_list, batch_params->chan_list, ++ sizeof(_params->params_batch.chan_list)); ++ ++ memset(_chan_list, 0, sizeof(_chan_list)); ++ ++ rem_nchan = ARRAYSIZE(batch_params->chan_list) - batch_params->nchan; ++ if (batch_params->band == WLC_BAND_2G || batch_params->band == WLC_BAND_5G) { ++ /* get a valid channel list based on band B or A */ ++ err = _dhd_pno_get_channels(dhd, ++ &_params->params_batch.chan_list[batch_params->nchan], ++ &rem_nchan, batch_params->band, FALSE); ++ if (err < 0) { ++ AP6211_ERR("%s: failed to get valid channel list(band : %d)\n", ++ __FUNCTION__, batch_params->band); ++ goto exit; ++ } ++ /* now we need to update nchan because rem_chan has valid channel count */ ++ _params->params_batch.nchan += rem_nchan; ++ /* need to sort channel list */ ++ sort(_params->params_batch.chan_list, _params->params_batch.nchan, ++ sizeof(_params->params_batch.chan_list[0]), _dhd_pno_cmpfunc, NULL); ++ } ++#ifdef PNO_DEBUG ++{ ++ AP6211_DEBUG("Channel list : "); ++ for (i = 0; i < _params->params_batch.nchan; i++) { ++ AP6211_DEBUG("%d ", _params->params_batch.chan_list[i]); ++ } ++ AP6211_DEBUG("\n"); ++} ++#endif ++ if (_params->params_batch.nchan) { ++ /* copy the channel list into local array */ ++ memcpy(_chan_list, _params->params_batch.chan_list, sizeof(_chan_list)); ++ tot_nchan = _params->params_batch.nchan; ++ } ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { ++ struct dhd_pno_ssid *iter, *next; ++ AP6211_DEBUG("PNO SSID is on progress in firmware\n"); ++ /* store current pno_mode before disabling pno */ ++ mode = _pno_state->pno_mode; ++ err = _dhd_pno_enable(dhd, PNO_OFF); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to disable PNO\n", __FUNCTION__); ++ goto exit; ++ } ++ /* restore the previous mode */ ++ _pno_state->pno_mode = mode; ++ /* Use the superset for channelist between two mode */ ++ _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); ++ if (_params2->params_legacy.nchan > 0 && _params->params_batch.nchan > 0) { ++ err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, ++ &_params2->params_legacy.chan_list[0], ++ _params2->params_legacy.nchan, ++ &_params->params_batch.chan_list[0], _params->params_batch.nchan); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to merge channel list" ++ " between legacy and batch\n", ++ __FUNCTION__); ++ goto exit; ++ } ++ } else { ++ AP6211_DEBUG("superset channel will use all channels in firmware\n"); ++ } ++ p_ssid_list = kzalloc(sizeof(wlc_ssid_t) * ++ _params2->params_legacy.nssid, GFP_KERNEL); ++ if (p_ssid_list == NULL) { ++ AP6211_ERR("%s : failed to allocate wlc_ssid_t array (count: %d)", ++ __FUNCTION__, _params2->params_legacy.nssid); ++ err = BCME_ERROR; ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++ goto exit; ++ } ++ i = 0; ++ /* convert dhd_pno_ssid to dhd_pno_ssid */ ++ list_for_each_entry_safe(iter, next, &_params2->params_legacy.ssid_list, list) { ++ p_ssid_list[i].SSID_len = iter->SSID_len; ++ memcpy(p_ssid_list->SSID, iter->SSID, p_ssid_list[i].SSID_len); ++ i++; ++ } ++ if ((err = _dhd_pno_add_ssid(dhd, p_ssid_list, ++ _params2->params_legacy.nssid)) < 0) { ++ AP6211_ERR("failed to add ssid list (err %d) in firmware\n", err); ++ goto exit; ++ } ++ } ++ if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_BATCH_MODE)) < 0) { ++ AP6211_ERR("%s : failed to set call pno_set (err %d) in firmware\n", ++ __FUNCTION__, err); ++ goto exit; ++ } else { ++ /* we need to return mscan */ ++ mscan = err; ++ } ++ if (tot_nchan > 0) { ++ if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { ++ AP6211_ERR("%s : failed to set call pno_cfg (err %d) in firmware\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++ if (_pno_state->pno_status == DHD_PNO_DISABLED) { ++ if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) ++ AP6211_ERR("%s : failed to enable PNO\n", __FUNCTION__); ++ } ++exit: ++ /* clear mode in case of error */ ++ if (err < 0) ++ _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; ++ else { ++ /* return #max scan firmware can do */ ++ err = mscan; ++ } ++ if (p_ssid_list) ++ kfree(p_ssid_list); ++ return err; ++} ++ ++static int ++_dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) ++{ ++ int err = BCME_OK; ++ int i, j; ++ uint32 timestamp = 0; ++ dhd_pno_params_t *_params = NULL; ++ dhd_pno_status_info_t *_pno_state = NULL; ++ wl_pfn_lscanresults_t *plbestnet = NULL; ++ wl_pfn_lnet_info_t *plnetinfo; ++ dhd_pno_bestnet_entry_t *pbestnet_entry; ++ dhd_pno_best_header_t *pbestnetheader = NULL; ++ dhd_pno_scan_results_t *pscan_results = NULL, *siter, *snext; ++ bool allocate_header = FALSE; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ ++ if (!WLS_SUPPORTED(_pno_state)) { ++ AP6211_ERR("%s : wifi location service is not supported\n", __FUNCTION__); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { ++ AP6211_ERR("%s: Batching SCAN mode is not enabled\n", __FUNCTION__); ++ goto exit; ++ } ++ mutex_lock(&_pno_state->pno_mutex); ++ _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; ++ if (buf && bufsize) { ++ if (!list_empty(&_params->params_batch.get_batch.expired_scan_results_list)) { ++ /* need to check whether we have cashed data or not */ ++ AP6211_DEBUG("%s: have cashed batching data in Driver\n", ++ __FUNCTION__); ++ /* convert to results format */ ++ goto convert_format; ++ } else { ++ /* this is a first try to get batching results */ ++ if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { ++ /* move the scan_results_list to expired_scan_results_lists */ ++ list_for_each_entry_safe(siter, snext, ++ &_params->params_batch.get_batch.scan_results_list, list) { ++ list_move_tail(&siter->list, ++ &_params->params_batch.get_batch.expired_scan_results_list); ++ } ++ _params->params_batch.get_batch.top_node_cnt = 0; ++ _params->params_batch.get_batch.expired_tot_scan_cnt = ++ _params->params_batch.get_batch.tot_scan_cnt; ++ _params->params_batch.get_batch.tot_scan_cnt = 0; ++ goto convert_format; ++ } ++ } ++ } ++ /* create dhd_pno_scan_results_t whenever we got event WLC_E_PFN_BEST_BATCHING */ ++ pscan_results = (dhd_pno_scan_results_t *)MALLOC(dhd->osh, SCAN_RESULTS_SIZE); ++ if (pscan_results == NULL) { ++ err = BCME_NOMEM; ++ AP6211_ERR("failed to allocate dhd_pno_scan_results_t\n"); ++ goto exit; ++ } ++ pscan_results->bestnetheader = NULL; ++ pscan_results->cnt_header = 0; ++ /* add the element into list unless total node cnt is less than MAX_NODE_ CNT */ ++ if (_params->params_batch.get_batch.top_node_cnt < MAX_NODE_CNT) { ++ list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); ++ _params->params_batch.get_batch.top_node_cnt++; ++ } else { ++ int _removed_scan_cnt; ++ /* remove oldest one and add new one */ ++ AP6211_DEBUG("%s : Remove oldest node and add new one\n", __FUNCTION__); ++ _removed_scan_cnt = _dhd_pno_clear_all_batch_results(dhd, ++ &_params->params_batch.get_batch.scan_results_list, TRUE); ++ _params->params_batch.get_batch.tot_scan_cnt -= _removed_scan_cnt; ++ list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); ++ ++ } ++ plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); ++ NULL_CHECK(plbestnet, "failed to allocate buffer for bestnet", err); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ memset(plbestnet, 0, PNO_BESTNET_LEN); ++ while (plbestnet->status != PFN_COMPLETE) { ++ memset(plbestnet, 0, PNO_BESTNET_LEN); ++ err = dhd_iovar(dhd, 0, "pfnlbest", (char *)plbestnet, PNO_BESTNET_LEN, 0); ++ if (err < 0) { ++ if (err == BCME_EPERM) { ++ AP6211_ERR("we cannot get the batching data " ++ "during scanning in firmware, try again\n,"); ++ msleep(500); ++ continue; ++ } else { ++ AP6211_ERR("%s : failed to execute pfnlbest (err :%d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++ AP6211_DEBUG("ver %d, status : %d, count %d\n", plbestnet->version, ++ plbestnet->status, plbestnet->count); ++ if (plbestnet->version != PFN_SCANRESULT_VERSION) { ++ err = BCME_VERSION; ++ AP6211_ERR("bestnet version(%d) is mismatch with Driver version(%d)\n", ++ plbestnet->version, PFN_SCANRESULT_VERSION); ++ goto exit; ++ } ++ plnetinfo = plbestnet->netinfo; ++ for (i = 0; i < plbestnet->count; i++) { ++ pbestnet_entry = (dhd_pno_bestnet_entry_t *) ++ MALLOC(dhd->osh, BESTNET_ENTRY_SIZE); ++ if (pbestnet_entry == NULL) { ++ err = BCME_NOMEM; ++ AP6211_ERR("failed to allocate dhd_pno_bestnet_entry\n"); ++ goto exit; ++ } ++ pbestnet_entry->recorded_time = jiffies; /* record the current time */ ++ /* create header for the first entry */ ++ allocate_header = (i == 0)? TRUE : FALSE; ++ /* check whether the new generation is started or not */ ++ if (timestamp && (TIME_DIFF(timestamp, plnetinfo->timestamp) ++ > TIME_MIN_DIFF)) ++ allocate_header = TRUE; ++ timestamp = plnetinfo->timestamp; ++ if (allocate_header) { ++ pbestnetheader = (dhd_pno_best_header_t *) ++ MALLOC(dhd->osh, BEST_HEADER_SIZE); ++ if (pbestnetheader == NULL) { ++ err = BCME_NOMEM; ++ if (pbestnet_entry) ++ MFREE(dhd->osh, pbestnet_entry, ++ BESTNET_ENTRY_SIZE); ++ AP6211_ERR("failed to allocate dhd_pno_bestnet_entry\n"); ++ goto exit; ++ } ++ /* increase total cnt of bestnet header */ ++ pscan_results->cnt_header++; ++ /* need to record the reason to call dhd_pno_get_for_bach */ ++ if (reason) ++ pbestnetheader->reason = (ENABLE << reason); ++ memset(pbestnetheader, 0, BEST_HEADER_SIZE); ++ /* initialize the head of linked list */ ++ INIT_LIST_HEAD(&(pbestnetheader->entry_list)); ++ /* link the pbestnet heaer into existed list */ ++ if (pscan_results->bestnetheader == NULL) ++ /* In case of header */ ++ pscan_results->bestnetheader = pbestnetheader; ++ else { ++ dhd_pno_best_header_t *head = pscan_results->bestnetheader; ++ pscan_results->bestnetheader = pbestnetheader; ++ pbestnetheader->next = head; ++ } ++ } ++ /* fills the best network info */ ++ pbestnet_entry->channel = plnetinfo->pfnsubnet.channel; ++ pbestnet_entry->RSSI = plnetinfo->RSSI; ++ if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { ++ /* if RSSI is positive value, we assume that ++ * this scan is aborted by other scan ++ */ ++ AP6211_DEBUG("This scan is aborted\n"); ++ pbestnetheader->reason = (ENABLE << PNO_STATUS_ABORT); ++ } ++ pbestnet_entry->rtt0 = plnetinfo->rtt0; ++ pbestnet_entry->rtt1 = plnetinfo->rtt1; ++ pbestnet_entry->timestamp = plnetinfo->timestamp; ++ pbestnet_entry->SSID_len = plnetinfo->pfnsubnet.SSID_len; ++ memcpy(pbestnet_entry->SSID, plnetinfo->pfnsubnet.SSID, ++ pbestnet_entry->SSID_len); ++ memcpy(&pbestnet_entry->BSSID, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN); ++ /* add the element into list */ ++ list_add_tail(&pbestnet_entry->list, &pbestnetheader->entry_list); ++ /* increase best entry count */ ++ pbestnetheader->tot_cnt++; ++ pbestnetheader->tot_size += BESTNET_ENTRY_SIZE; ++ AP6211_DEBUG("Header %d\n", pscan_results->cnt_header - 1); ++ AP6211_DEBUG("\tSSID : "); ++ for (j = 0; j < plnetinfo->pfnsubnet.SSID_len; j++) ++ AP6211_DEBUG("%c", plnetinfo->pfnsubnet.SSID[j]); ++ AP6211_DEBUG("\n"); ++ AP6211_DEBUG("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ plnetinfo->pfnsubnet.BSSID.octet[0], ++ plnetinfo->pfnsubnet.BSSID.octet[1], ++ plnetinfo->pfnsubnet.BSSID.octet[2], ++ plnetinfo->pfnsubnet.BSSID.octet[3], ++ plnetinfo->pfnsubnet.BSSID.octet[4], ++ plnetinfo->pfnsubnet.BSSID.octet[5]); ++ AP6211_DEBUG("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", ++ plnetinfo->pfnsubnet.channel, ++ plnetinfo->RSSI, plnetinfo->timestamp); ++ AP6211_DEBUG("\tRTT0 : %d, RTT1: %d\n", plnetinfo->rtt0, plnetinfo->rtt1); ++ plnetinfo++; ++ } ++ } ++ /* increase total scan count using current scan count */ ++ _params->params_batch.get_batch.tot_scan_cnt += pscan_results->cnt_header; ++ ++ if (buf && bufsize) { ++ /* This is a first try to get batching results */ ++ if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { ++ /* move the scan_results_list to expired_scan_results_lists */ ++ list_for_each_entry_safe(siter, snext, ++ &_params->params_batch.get_batch.scan_results_list, list) { ++ list_move_tail(&siter->list, ++ &_params->params_batch.get_batch.expired_scan_results_list); ++ } ++ /* reset gloval values after moving to expired list */ ++ _params->params_batch.get_batch.top_node_cnt = 0; ++ _params->params_batch.get_batch.expired_tot_scan_cnt = ++ _params->params_batch.get_batch.tot_scan_cnt; ++ _params->params_batch.get_batch.tot_scan_cnt = 0; ++ } ++convert_format: ++ err = _dhd_pno_convert_format(dhd, &_params->params_batch, buf, bufsize); ++ if (err < 0) { ++ AP6211_ERR("failed to convert the data into upper layer format\n"); ++ goto exit; ++ } ++ } ++exit: ++ if (plbestnet) ++ MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN); ++ _params->params_batch.get_batch.buf = NULL; ++ _params->params_batch.get_batch.bufsize = 0; ++ mutex_unlock(&_pno_state->pno_mutex); ++ complete(&_pno_state->get_batch_done); ++ return err; ++} ++static void ++_dhd_pno_get_batch_handler(struct work_struct *work) ++{ ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pub_t *dhd; ++ struct dhd_pno_batch_params *params_batch; ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ _pno_state = container_of(work, struct dhd_pno_status_info, work); ++ dhd = _pno_state->dhd; ++ if (dhd == NULL) { ++ AP6211_ERR("%s : dhd is NULL\n", __FUNCTION__); ++ return; ++ } ++ params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; ++ _dhd_pno_get_for_batch(dhd, params_batch->get_batch.buf, ++ params_batch->get_batch.bufsize, params_batch->get_batch.reason); ++ ++} ++ ++int ++dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) ++{ ++ int err = BCME_OK; ++ dhd_pno_status_info_t *_pno_state; ++ struct dhd_pno_batch_params *params_batch; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ ++ if (!WLS_SUPPORTED(_pno_state)) { ++ AP6211_ERR("%s : wifi location service is not supported\n", __FUNCTION__); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; ++ if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { ++ AP6211_ERR("%s: Batching SCAN mode is not enabled\n", __FUNCTION__); ++ goto exit; ++ } ++ params_batch->get_batch.buf = buf; ++ params_batch->get_batch.bufsize = bufsize; ++ params_batch->get_batch.reason = reason; ++ schedule_work(&_pno_state->work); ++ wait_for_completion(&_pno_state->get_batch_done); ++exit: ++ return err; ++} ++ ++int ++dhd_pno_stop_for_batch(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ int mode = 0; ++ int i = 0; ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pno_params_t *_params; ++ wl_pfn_bssid_t *p_pfn_bssid; ++ wlc_ssid_t *p_ssid_list = NULL; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ if (!WLS_SUPPORTED(_pno_state)) { ++ AP6211_ERR("%s : wifi location service is not supported\n", ++ __FUNCTION__); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { ++ AP6211_ERR("%s : PNO BATCH MODE is not enabled\n", __FUNCTION__); ++ goto exit; ++ } ++ _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; ++ if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_HOTLIST_MODE)) { ++ mode = _pno_state->pno_mode; ++ _dhd_pno_clean(dhd); ++ _pno_state->pno_mode = mode; ++ /* restart Legacy PNO if the Legacy PNO is on */ ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { ++ struct dhd_pno_legacy_params *_params_legacy; ++ struct dhd_pno_ssid *iter, *next; ++ _params_legacy = ++ &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); ++ p_ssid_list = kzalloc(sizeof(wlc_ssid_t) * ++ _params_legacy->nssid, GFP_KERNEL); ++ if (p_ssid_list == NULL) { ++ AP6211_ERR("%s : failed to allocate wlc_ssid_t array (count: %d)", ++ __FUNCTION__, _params_legacy->nssid); ++ err = BCME_ERROR; ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++ goto exit; ++ } ++ i = 0; ++ /* convert dhd_pno_ssid to dhd_pno_ssid */ ++ list_for_each_entry_safe(iter, next, &_params_legacy->ssid_list, list) { ++ p_ssid_list[i].SSID_len = iter->SSID_len; ++ memcpy(p_ssid_list[i].SSID, iter->SSID, p_ssid_list[i].SSID_len); ++ i++; ++ } ++ err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, ++ _params_legacy->scan_fr, _params_legacy->pno_repeat, ++ _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, ++ _params_legacy->nchan); ++ if (err < 0) { ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++ AP6211_ERR("%s : failed to restart legacy PNO scan(err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { ++ struct dhd_pno_bssid *iter, *next; ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); ++ p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * ++ _params->params_hotlist.nbssid, GFP_KERNEL); ++ if (p_pfn_bssid == NULL) { ++ AP6211_ERR("%s : failed to allocate wl_pfn_bssid_t array" ++ " (count: %d)", ++ __FUNCTION__, _params->params_hotlist.nbssid); ++ err = BCME_ERROR; ++ _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; ++ goto exit; ++ } ++ i = 0; ++ /* convert dhd_pno_bssid to wl_pfn_bssid */ ++ list_for_each_entry_safe(iter, next, ++ &_params->params_hotlist.bssid_list, list) { ++ memcpy(&p_pfn_bssid[i].macaddr, &iter->macaddr, ETHER_ADDR_LEN); ++ p_pfn_bssid[i].flags = iter->flags; ++ i++; ++ } ++ err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); ++ if (err < 0) { ++ _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; ++ AP6211_ERR("%s : failed to restart hotlist scan(err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++ } else { ++ err = _dhd_pno_clean(dhd); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to call _dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++exit: ++ _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; ++ _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); ++ if (p_ssid_list) ++ kfree(p_ssid_list); ++ return err; ++} ++ ++int ++dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, ++ struct dhd_pno_hotlist_params *hotlist_params) ++{ ++ int err = BCME_OK; ++ int i; ++ uint16 _chan_list[WL_NUMCHANNELS]; ++ int rem_nchan = 0; ++ int tot_nchan = 0; ++ int mode = 0; ++ dhd_pno_params_t *_params; ++ dhd_pno_params_t *_params2; ++ struct dhd_pno_bssid *_pno_bssid; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ NULL_CHECK(hotlist_params, "hotlist_params is NULL", err); ++ NULL_CHECK(p_pfn_bssid, "p_pfn_bssid is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ if (!WLS_SUPPORTED(_pno_state)) { ++ AP6211_ERR("%s : wifi location service is not supported\n", __FUNCTION__); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ _params = &_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]; ++ if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) { ++ _pno_state->pno_mode |= DHD_PNO_HOTLIST_MODE; ++ err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_HOTLIST_MODE); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to call _dhd_pno_reinitialize_prof\n", ++ __FUNCTION__); ++ goto exit; ++ } ++ } ++ _params->params_batch.nchan = hotlist_params->nchan; ++ _params->params_batch.scan_fr = hotlist_params->scan_fr; ++ if (hotlist_params->nchan) ++ memcpy(_params->params_hotlist.chan_list, hotlist_params->chan_list, ++ sizeof(_params->params_hotlist.chan_list)); ++ memset(_chan_list, 0, sizeof(_chan_list)); ++ ++ rem_nchan = ARRAYSIZE(hotlist_params->chan_list) - hotlist_params->nchan; ++ if (hotlist_params->band == WLC_BAND_2G || hotlist_params->band == WLC_BAND_5G) { ++ /* get a valid channel list based on band B or A */ ++ err = _dhd_pno_get_channels(dhd, ++ &_params->params_hotlist.chan_list[hotlist_params->nchan], ++ &rem_nchan, hotlist_params->band, FALSE); ++ if (err < 0) { ++ AP6211_ERR("%s: failed to get valid channel list(band : %d)\n", ++ __FUNCTION__, hotlist_params->band); ++ goto exit; ++ } ++ /* now we need to update nchan because rem_chan has valid channel count */ ++ _params->params_hotlist.nchan += rem_nchan; ++ /* need to sort channel list */ ++ sort(_params->params_hotlist.chan_list, _params->params_hotlist.nchan, ++ sizeof(_params->params_hotlist.chan_list[0]), _dhd_pno_cmpfunc, NULL); ++ } ++#ifdef PNO_DEBUG ++{ ++ int i; ++ AP6211_DEBUG("Channel list : "); ++ for (i = 0; i < _params->params_batch.nchan; i++) { ++ AP6211_DEBUG("%d ", _params->params_batch.chan_list[i]); ++ } ++ AP6211_DEBUG("\n"); ++} ++#endif ++ if (_params->params_hotlist.nchan) { ++ /* copy the channel list into local array */ ++ memcpy(_chan_list, _params->params_hotlist.chan_list, ++ sizeof(_chan_list)); ++ tot_nchan = _params->params_hotlist.nchan; ++ } ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { ++ AP6211_DEBUG("PNO SSID is on progress in firmware\n"); ++ /* store current pno_mode before disabling pno */ ++ mode = _pno_state->pno_mode; ++ err = _dhd_pno_enable(dhd, PNO_OFF); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to disable PNO\n", __FUNCTION__); ++ goto exit; ++ } ++ /* restore the previous mode */ ++ _pno_state->pno_mode = mode; ++ /* Use the superset for channelist between two mode */ ++ _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); ++ if (_params2->params_legacy.nchan > 0 && ++ _params->params_hotlist.nchan > 0) { ++ err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, ++ &_params2->params_legacy.chan_list[0], ++ _params2->params_legacy.nchan, ++ &_params->params_hotlist.chan_list[0], ++ _params->params_hotlist.nchan); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to merge channel list" ++ "between legacy and hotlist\n", ++ __FUNCTION__); ++ goto exit; ++ } ++ } ++ ++ } ++ ++ INIT_LIST_HEAD(&(_params->params_hotlist.bssid_list)); ++ ++ err = _dhd_pno_add_bssid(dhd, p_pfn_bssid, hotlist_params->nbssid); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to call _dhd_pno_add_bssid(err :%d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_HOTLIST_MODE)) < 0) { ++ AP6211_ERR("%s : failed to set call pno_set (err %d) in firmware\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ if (tot_nchan > 0) { ++ if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { ++ AP6211_ERR("%s : failed to set call pno_cfg (err %d) in firmware\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++ for (i = 0; i < hotlist_params->nbssid; i++) { ++ _pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), GFP_KERNEL); ++ NULL_CHECK(_pno_bssid, "_pfn_bssid is NULL", err); ++ memcpy(&_pno_bssid->macaddr, &p_pfn_bssid[i].macaddr, ETHER_ADDR_LEN); ++ _pno_bssid->flags = p_pfn_bssid[i].flags; ++ list_add_tail(&_pno_bssid->list, &_params->params_hotlist.bssid_list); ++ } ++ _params->params_hotlist.nbssid = hotlist_params->nbssid; ++ if (_pno_state->pno_status == DHD_PNO_DISABLED) { ++ if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) ++ AP6211_ERR("%s : failed to enable PNO\n", __FUNCTION__); ++ } ++exit: ++ /* clear mode in case of error */ ++ if (err < 0) ++ _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; ++ return err; ++} ++ ++int ++dhd_pno_stop_for_hotlist(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ uint32 mode = 0; ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pno_params_t *_params; ++ wlc_ssid_t *p_ssid_list; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ ++ if (!WLS_SUPPORTED(_pno_state)) { ++ AP6211_ERR("%s : wifi location service is not supported\n", ++ __FUNCTION__); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ ++ if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) { ++ AP6211_ERR("%s : Hotlist MODE is not enabled\n", ++ __FUNCTION__); ++ goto exit; ++ } ++ _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; ++ ++ if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_BATCH_MODE)) { ++ /* retrieve the batching data from firmware into host */ ++ dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); ++ /* save current pno_mode before calling dhd_pno_clean */ ++ mode = _pno_state->pno_mode; ++ err = _dhd_pno_clean(dhd); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to call _dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ /* restore previos pno mode */ ++ _pno_state->pno_mode = mode; ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { ++ /* restart Legacy PNO Scan */ ++ struct dhd_pno_legacy_params *_params_legacy; ++ struct dhd_pno_ssid *iter, *next; ++ _params_legacy = ++ &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); ++ p_ssid_list = ++ kzalloc(sizeof(wlc_ssid_t) * _params_legacy->nssid, GFP_KERNEL); ++ if (p_ssid_list == NULL) { ++ AP6211_ERR("%s : failed to allocate wlc_ssid_t array (count: %d)", ++ __FUNCTION__, _params_legacy->nssid); ++ err = BCME_ERROR; ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++ goto exit; ++ } ++ /* convert dhd_pno_ssid to dhd_pno_ssid */ ++ list_for_each_entry_safe(iter, next, &_params_legacy->ssid_list, list) { ++ p_ssid_list->SSID_len = iter->SSID_len; ++ memcpy(p_ssid_list->SSID, iter->SSID, p_ssid_list->SSID_len); ++ p_ssid_list++; ++ } ++ err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, ++ _params_legacy->scan_fr, _params_legacy->pno_repeat, ++ _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, ++ _params_legacy->nchan); ++ if (err < 0) { ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++ AP6211_ERR("%s : failed to restart legacy PNO scan(err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } else if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ /* restart Batching Scan */ ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); ++ /* restart BATCH SCAN */ ++ err = dhd_pno_set_for_batch(dhd, &_params->params_batch); ++ if (err < 0) { ++ _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; ++ AP6211_ERR("%s : failed to restart batch scan(err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++ } else { ++ err = _dhd_pno_clean(dhd); ++ if (err < 0) { ++ AP6211_ERR("%s : failed to call _dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, err); ++ goto exit; ++ } ++ } ++exit: ++ return err; ++} ++ ++int ++dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) ++{ ++ int err = BCME_OK; ++ uint status, event_type, flags, datalen; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ if (!WLS_SUPPORTED(_pno_state)) { ++ AP6211_ERR("%s : wifi location service is not supported\n", __FUNCTION__); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ event_type = ntoh32(event->event_type); ++ flags = ntoh16(event->flags); ++ status = ntoh32(event->status); ++ datalen = ntoh32(event->datalen); ++ AP6211_DEBUG("%s enter : event_type :%d\n", __FUNCTION__, event_type); ++ switch (event_type) { ++ case WLC_E_PFN_BSSID_NET_FOUND: ++ case WLC_E_PFN_BSSID_NET_LOST: ++ /* XXX : how can we inform this to framework ? */ ++ /* TODO : need to implement event logic using generic netlink */ ++ break; ++ case WLC_E_PFN_BEST_BATCHING: ++ { ++ struct dhd_pno_batch_params *params_batch; ++ params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; ++ AP6211_DEBUG("%s : WLC_E_PFN_BEST_BATCHING\n", __FUNCTION__); ++ params_batch->get_batch.buf = NULL; ++ params_batch->get_batch.bufsize = 0; ++ params_batch->get_batch.reason = PNO_STATUS_EVENT; ++ schedule_work(&_pno_state->work); ++ break; ++ } ++ default: ++ AP6211_ERR("unknown event : %d\n", event_type); ++ } ++exit: ++ return err; ++} ++ ++int dhd_pno_init(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ UNUSED_PARAMETER(_dhd_pno_suspend); ++ if (dhd->pno_state) ++ goto exit; ++ dhd->pno_state = MALLOC(dhd->osh, sizeof(dhd_pno_status_info_t)); ++ memset(dhd->pno_state, 0, sizeof(dhd_pno_status_info_t)); ++ NULL_CHECK(dhd, "failed to create dhd_pno_state", err); ++ /* need to check whether current firmware support batching and hotlist scan */ ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ _pno_state->wls_supported = TRUE; ++ _pno_state->dhd = dhd; ++ mutex_init(&_pno_state->pno_mutex); ++ INIT_WORK(&_pno_state->work, _dhd_pno_get_batch_handler); ++ init_completion(&_pno_state->get_batch_done); ++ err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, 0); ++ if (err == BCME_UNSUPPORTED) { ++ _pno_state->wls_supported = FALSE; ++ AP6211_DEBUG("Current firmware doesn't support" ++ " Android Location Service\n"); ++ } ++exit: ++ return err; ++} ++int dhd_pno_deinit(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ AP6211_DEBUG("%s enter\n", __FUNCTION__); ++ cancel_work_sync(&_pno_state->work); ++ if (dhd->pno_state) ++ MFREE(dhd->osh, dhd->pno_state, sizeof(dhd_pno_status_info_t)); ++ dhd->pno_state = NULL; ++ return err; ++} +diff --git a/drivers/net/wireless/ap6211/dhd_pno.h b/drivers/net/wireless/ap6211/dhd_pno.h +new file mode 100755 +index 0000000..1e02db1 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_pno.h +@@ -0,0 +1,249 @@ ++/* ++ * Header file of Broadcom Dongle Host Driver (DHD) ++ * Prefered Network Offload code and Wi-Fi Location Service(WLS) code. ++ * Copyright (C) 1999-2013, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_pno.h 419969 2013-08-23 18:54:36Z $ ++ */ ++ ++#ifndef __DHD_PNO_H__ ++#define __DHD_PNO_H__ ++ ++#define PNO_TLV_PREFIX 'S' ++#define PNO_TLV_VERSION '1' ++#define PNO_TLV_SUBTYPE_LEGACY_PNO '2' ++#define PNO_TLV_RESERVED '0' ++ ++#define PNO_BATCHING_SET "SET" ++#define PNO_BATCHING_GET "GET" ++#define PNO_BATCHING_STOP "STOP" ++ ++#define PNO_PARAMS_DELIMETER " " ++#define PNO_PARAM_CHANNEL_DELIMETER "," ++#define PNO_PARAM_VALUE_DELLIMETER '=' ++#define PNO_PARAM_SCANFREQ "SCANFREQ" ++#define PNO_PARAM_BESTN "BESTN" ++#define PNO_PARAM_MSCAN "MSCAN" ++#define PNO_PARAM_CHANNEL "CHANNEL" ++#define PNO_PARAM_RTT "RTT" ++ ++#define PNO_TLV_TYPE_SSID_IE 'S' ++#define PNO_TLV_TYPE_TIME 'T' ++#define PNO_TLV_FREQ_REPEAT 'R' ++#define PNO_TLV_FREQ_EXPO_MAX 'M' ++ ++#define MAXNUM_SSID_PER_ADD 16 ++#define MAXNUM_PNO_PARAMS 2 ++#define PNO_TLV_COMMON_LENGTH 1 ++#define DEFAULT_BATCH_MSCAN 16 ++ ++#define RESULTS_END_MARKER "----\n" ++#define SCAN_END_MARKER "####\n" ++#define AP_END_MARKER "====\n" ++ ++enum scan_status { ++ /* SCAN ABORT by other scan */ ++ PNO_STATUS_ABORT, ++ /* RTT is presence or not */ ++ PNO_STATUS_RTT_PRESENCE, ++ /* Disable PNO by Driver */ ++ PNO_STATUS_DISABLE, ++ /* NORMAL BATCHING GET */ ++ PNO_STATUS_NORMAL, ++ /* WLC_E_PFN_BEST_BATCHING */ ++ PNO_STATUS_EVENT, ++ PNO_STATUS_MAX ++}; ++#define PNO_STATUS_ABORT_MASK 0x0001 ++#define PNO_STATUS_RTT_MASK 0x0002 ++#define PNO_STATUS_DISABLE_MASK 0x0004 ++#define PNO_STATUS_OOM_MASK 0x0010 ++ ++enum index_mode { ++ INDEX_OF_LEGACY_PARAMS, ++ INDEX_OF_BATCH_PARAMS, ++ INDEX_OF_HOTLIST_PARAMS, ++ INDEX_MODE_MAX ++}; ++enum dhd_pno_status { ++ DHD_PNO_DISABLED, ++ DHD_PNO_ENABLED, ++ DHD_PNO_SUSPEND ++}; ++typedef struct cmd_tlv { ++ char prefix; ++ char version; ++ char subtype; ++ char reserved; ++} cmd_tlv_t; ++typedef enum dhd_pno_mode { ++ /* Wi-Fi Legacy PNO Mode */ ++ DHD_PNO_NONE_MODE = 0, ++ DHD_PNO_LEGACY_MODE = (1 << (0)), ++ /* Wi-Fi Android BATCH SCAN Mode */ ++ DHD_PNO_BATCH_MODE = (1 << (1)), ++ /* Wi-Fi Android Hotlist SCAN Mode */ ++ DHD_PNO_HOTLIST_MODE = (1 << (2)) ++} dhd_pno_mode_t; ++struct dhd_pno_ssid { ++ uint32 SSID_len; ++ uchar SSID[DOT11_MAX_SSID_LEN]; ++ struct list_head list; ++}; ++struct dhd_pno_bssid { ++ struct ether_addr macaddr; ++ /* Bit4: suppress_lost, Bit3: suppress_found */ ++ uint16 flags; ++ struct list_head list; ++}; ++typedef struct dhd_pno_bestnet_entry { ++ struct ether_addr BSSID; ++ uint8 SSID_len; ++ uint8 SSID[DOT11_MAX_SSID_LEN]; ++ int8 RSSI; ++ uint8 channel; ++ uint32 timestamp; ++ uint16 rtt0; /* distance_cm based on RTT */ ++ uint16 rtt1; /* distance_cm based on sample standard deviation */ ++ unsigned long recorded_time; ++ struct list_head list; ++} dhd_pno_bestnet_entry_t; ++#define BESTNET_ENTRY_SIZE (sizeof(dhd_pno_bestnet_entry_t)) ++ ++typedef struct dhd_pno_bestnet_header { ++ struct dhd_pno_bestnet_header *next; ++ uint8 reason; ++ uint32 tot_cnt; ++ uint32 tot_size; ++ struct list_head entry_list; ++} dhd_pno_best_header_t; ++#define BEST_HEADER_SIZE (sizeof(dhd_pno_best_header_t)) ++ ++typedef struct dhd_pno_scan_results { ++ dhd_pno_best_header_t *bestnetheader; ++ uint8 cnt_header; ++ struct list_head list; ++} dhd_pno_scan_results_t; ++#define SCAN_RESULTS_SIZE (sizeof(dhd_pno_scan_results_t)) ++ ++struct dhd_pno_get_batch_info { ++ /* info related to get batch */ ++ char *buf; ++ bool batch_started; ++ uint32 tot_scan_cnt; ++ uint32 expired_tot_scan_cnt; ++ uint32 top_node_cnt; ++ uint32 bufsize; ++ int reason; ++ struct list_head scan_results_list; ++ struct list_head expired_scan_results_list; ++}; ++struct dhd_pno_legacy_params { ++ uint16 scan_fr; ++ uint16 chan_list[WL_NUMCHANNELS]; ++ uint16 nchan; ++ int pno_repeat; ++ int pno_freq_expo_max; ++ int nssid; ++ struct list_head ssid_list; ++}; ++struct dhd_pno_batch_params { ++ int32 scan_fr; ++ uint8 bestn; ++ uint8 mscan; ++ uint8 band; ++ uint16 chan_list[WL_NUMCHANNELS]; ++ uint16 nchan; ++ uint16 rtt; ++ struct dhd_pno_get_batch_info get_batch; ++}; ++struct dhd_pno_hotlist_params { ++ uint8 band; ++ int32 scan_fr; ++ uint16 chan_list[WL_NUMCHANNELS]; ++ uint16 nchan; ++ uint16 nbssid; ++ struct list_head bssid_list; ++}; ++typedef union dhd_pno_params { ++ struct dhd_pno_legacy_params params_legacy; ++ struct dhd_pno_batch_params params_batch; ++ struct dhd_pno_hotlist_params params_hotlist; ++} dhd_pno_params_t; ++typedef struct dhd_pno_status_info { ++ dhd_pub_t *dhd; ++ struct work_struct work; ++ struct mutex pno_mutex; ++ struct completion get_batch_done; ++ bool wls_supported; /* wifi location service supported or not */ ++ enum dhd_pno_status pno_status; ++ enum dhd_pno_mode pno_mode; ++ dhd_pno_params_t pno_params_arr[INDEX_MODE_MAX]; ++ struct list_head head_list; ++} dhd_pno_status_info_t; ++ ++/* wrapper functions */ ++extern int ++dhd_dev_pno_enable(struct net_device *dev, int enable); ++ ++extern int ++dhd_dev_pno_stop_for_ssid(struct net_device *dev); ++ ++extern int ++dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, ++ uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); ++ ++extern int ++dhd_dev_pno_set_for_batch(struct net_device *dev, ++ struct dhd_pno_batch_params *batch_params); ++ ++extern int ++dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize); ++ ++extern int ++dhd_dev_pno_stop_for_batch(struct net_device *dev); ++ ++extern int ++dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid, ++ struct dhd_pno_hotlist_params *hotlist_params); ++ ++/* dhd pno fuctions */ ++extern int dhd_pno_stop_for_ssid(dhd_pub_t *dhd); ++extern int dhd_pno_enable(dhd_pub_t *dhd, int enable); ++extern int dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssid_list, int nssid, ++ uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); ++ ++extern int dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params); ++ ++extern int dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason); ++ ++ ++extern int dhd_pno_stop_for_batch(dhd_pub_t *dhd); ++ ++extern int dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, ++ struct dhd_pno_hotlist_params *hotlist_params); ++ ++extern int dhd_pno_stop_for_hotlist(dhd_pub_t *dhd); ++ ++extern int dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data); ++extern int dhd_pno_init(dhd_pub_t *dhd); ++extern int dhd_pno_deinit(dhd_pub_t *dhd); ++#endif /* __DHD_PNO_H__ */ +diff --git a/drivers/net/wireless/ap6211/dhd_proto.h b/drivers/net/wireless/ap6211/dhd_proto.h +new file mode 100755 +index 0000000..09d5468 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_proto.h +@@ -0,0 +1,113 @@ ++/* ++ * Header file describing the internal (inter-module) DHD interfaces. ++ * ++ * Provides type definitions and function prototypes used to link the ++ * DHD OS, bus, and protocol modules. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_proto.h 343390 2012-07-06 22:34:19Z $ ++ */ ++ ++#ifndef _dhd_proto_h_ ++#define _dhd_proto_h_ ++ ++#include ++#include ++ ++#ifndef IOCTL_RESP_TIMEOUT ++#define IOCTL_RESP_TIMEOUT 2000 /* In milli second default value for Production FW */ ++#endif /* IOCTL_RESP_TIMEOUT */ ++ ++/* ++ * Exported from the dhd protocol module (dhd_cdc, dhd_rndis) ++ */ ++ ++/* Linkage, sets prot link and updates hdrlen in pub */ ++extern int dhd_prot_attach(dhd_pub_t *dhdp); ++ ++/* Unlink, frees allocated protocol memory (including dhd_prot) */ ++extern void dhd_prot_detach(dhd_pub_t *dhdp); ++ ++/* Initialize protocol: sync w/dongle state. ++ * Sets dongle media info (iswl, drv_version, mac address). ++ */ ++extern int dhd_prot_init(dhd_pub_t *dhdp); ++ ++/* Stop protocol: sync w/dongle state. */ ++extern void dhd_prot_stop(dhd_pub_t *dhdp); ++#ifdef PROP_TXSTATUS ++extern int dhd_wlfc_init(dhd_pub_t *dhd); ++extern void dhd_wlfc_deinit(dhd_pub_t *dhd); ++#endif /* PROP_TXSTATUS */ ++ ++/* Add any protocol-specific data header. ++ * Caller must reserve prot_hdrlen prepend space. ++ */ ++extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp); ++ ++/* Remove any protocol-specific data header. */ ++extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp, uchar *buf, uint *len); ++ ++/* Use protocol to issue ioctl to dongle */ ++extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len); ++ ++/* Handles a protocol control response asynchronously */ ++extern int dhd_prot_ctl_complete(dhd_pub_t *dhd); ++ ++/* Check for and handle local prot-specific iovar commands */ ++extern int dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, ++ void *params, int plen, void *arg, int len, bool set); ++ ++/* Add prot dump output to a buffer */ ++extern void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); ++ ++/* Update local copy of dongle statistics */ ++extern void dhd_prot_dstats(dhd_pub_t *dhdp); ++ ++extern int dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen); ++ ++extern int dhd_preinit_ioctls(dhd_pub_t *dhd); ++ ++#ifdef PROP_TXSTATUS ++extern int dhd_wlfc_enque_sendq(void* state, int prec, void* p); ++extern int dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx); ++extern void dhd_wlfc_cleanup(dhd_pub_t *dhd); ++#endif /* PROP_TXSTATUS */ ++ ++extern int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, ++ uint reorder_info_len, void **pkt, uint32 *free_buf_count); ++ ++ ++/******************************** ++ * For version-string expansion * ++ */ ++#if defined(BDC) ++#define DHD_PROTOCOL "bdc" ++#elif defined(CDC) ++#define DHD_PROTOCOL "cdc" ++#elif defined(RNDIS) ++#define DHD_PROTOCOL "rndis" ++#else ++#define DHD_PROTOCOL "unknown" ++#endif /* proto */ ++ ++#endif /* _dhd_proto_h_ */ +diff --git a/drivers/net/wireless/ap6211/dhd_sdio.c b/drivers/net/wireless/ap6211/dhd_sdio.c +new file mode 100755 +index 0000000..786f287 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_sdio.c +@@ -0,0 +1,7856 @@ ++/* ++ * DHD Bus Module for SDIO ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_sdio.c 373330 2012-12-07 04:46:17Z $ ++ */ ++ ++#include ++#include ++#include ++ ++#ifdef BCMEMBEDIMAGE ++#include BCMEMBEDIMAGE ++#endif /* BCMEMBEDIMAGE */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#if defined(DHD_DEBUG) ++#include ++#include ++#endif /* defined(DHD_DEBUG) */ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#ifndef DHDSDIO_MEM_DUMP_FNAME ++#define DHDSDIO_MEM_DUMP_FNAME "mem_dump" ++#endif ++ ++#define QLEN 256 /* bulk rx and tx queue lengths */ ++#define FCHI (QLEN - 10) ++#define FCLOW (FCHI / 2) ++#define PRIOMASK 7 ++ ++#define TXRETRIES 2 /* # of retries for tx frames */ ++ ++#define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */ ++ ++#define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */ ++ ++#define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */ ++ ++#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ ++#define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */ ++#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold biggest possible glom */ ++ ++#ifndef DHD_FIRSTREAD ++#define DHD_FIRSTREAD 32 ++#endif ++#if !ISPOWEROF2(DHD_FIRSTREAD) ++#error DHD_FIRSTREAD is not a power of 2! ++#endif ++ ++#ifdef BCMSDIOH_TXGLOM ++/* Total length of TX frame header for dongle protocol */ ++#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + SDPCM_SWHEADER_LEN) ++/* Total length of RX frame for dongle protocol */ ++#else ++/* Total length of TX frame header for dongle protocol */ ++#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) ++#endif ++ ++#define SDPCM_HDRLEN_RX (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) ++ ++#ifdef SDTEST ++#define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN) ++#else ++#define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN) ++#endif ++ ++/* Space for header read, limit for data packets */ ++#ifndef MAX_HDR_READ ++#define MAX_HDR_READ 32 ++#endif ++#if !ISPOWEROF2(MAX_HDR_READ) ++#error MAX_HDR_READ is not a power of 2! ++#endif ++ ++#define MAX_RX_DATASZ 2048 ++ ++/* Maximum milliseconds to wait for F2 to come up */ ++#define DHD_WAIT_F2RDY 3000 ++ ++/* Bump up limit on waiting for HT to account for first startup; ++ * if the image is doing a CRC calculation before programming the PMU ++ * for HT availability, it could take a couple hundred ms more, so ++ * max out at a 1 second (1000000us). ++ */ ++#if (PMU_MAX_TRANSITION_DLY <= 1000000) ++#undef PMU_MAX_TRANSITION_DLY ++#define PMU_MAX_TRANSITION_DLY 1000000 ++#endif ++ ++/* Value for ChipClockCSR during initial setup */ ++#define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ) ++#define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP) ++ ++/* Flags for SDH calls */ ++#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) ++ ++/* Packet free applicable unconditionally for sdio and sdspi. Conditional if ++ * bufpool was present for gspi bus. ++ */ ++#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \ ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); ++#if defined(OOB_INTR_ONLY) ++extern void bcmsdh_set_irq(int flag); ++#endif ++#ifdef PROP_TXSTATUS ++extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success, bool wlfc_locked); ++extern void dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd); ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++DEFINE_MUTEX(_dhd_sdio_mutex_lock_); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ ++ ++#ifdef DHD_DEBUG ++/* Device console log buffer state */ ++#define CONSOLE_LINE_MAX 192 ++#define CONSOLE_BUFFER_MAX 2024 ++typedef struct dhd_console { ++ uint count; /* Poll interval msec counter */ ++ uint log_addr; /* Log struct address (fixed) */ ++ hndrte_log_t log; /* Log struct (host copy) */ ++ uint bufsize; /* Size of log buffer */ ++ uint8 *buf; /* Log buffer (host copy) */ ++ uint last; /* Last buffer read index */ ++} dhd_console_t; ++#endif /* DHD_DEBUG */ ++ ++#define REMAP_ENAB(bus) ((bus)->remap) ++#define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize))) ++#define KSO_ENAB(bus) ((bus)->kso) ++#define SR_ENAB(bus) ((bus)->_srenab) ++#define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto)) ++#define MIN_RSRC_ADDR (SI_ENUM_BASE + 0x618) ++#define MIN_RSRC_SR 0x3 ++#define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c) ++#define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1) ++#define RCTL_MACPHY_DISABLE_MASK (1 << 26) ++#define RCTL_LOGIC_DISABLE_MASK (1 << 27) ++ ++#define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup) ++#define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */ ++#define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */ ++#define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */ ++#define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0) ++ ++#define CC_PMUCC3 (0x3) ++/* Private data for SDIO bus interaction */ ++typedef struct dhd_bus { ++ dhd_pub_t *dhd; ++ ++ bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */ ++ si_t *sih; /* Handle for SI calls */ ++ char *vars; /* Variables (from CIS and/or other) */ ++ uint varsz; /* Size of variables buffer */ ++ uint32 sbaddr; /* Current SB window pointer (-1, invalid) */ ++ ++ sdpcmd_regs_t *regs; /* Registers for SDIO core */ ++ uint sdpcmrev; /* SDIO core revision */ ++ uint armrev; /* CPU core revision */ ++ uint ramrev; /* SOCRAM core revision */ ++ uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */ ++ uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */ ++ uint32 srmemsize; /* Size of SRMEM */ ++ ++ uint32 bus; /* gSPI or SDIO bus */ ++ uint32 hostintmask; /* Copy of Host Interrupt Mask */ ++ uint32 intstatus; /* Intstatus bits (events) pending */ ++ bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ ++ bool fcstate; /* State of dongle flow-control */ ++ ++ uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */ ++ char *fw_path; /* module_param: path to firmware image */ ++ char *nv_path; /* module_param: path to nvram vars file */ ++ const char *nvram_params; /* user specified nvram params. */ ++ ++ uint blocksize; /* Block size of SDIO transfers */ ++ uint roundup; /* Max roundup limit */ ++ ++ struct pktq txq; /* Queue length used for flow-control */ ++ uint8 flowcontrol; /* per prio flow control bitmask */ ++ uint8 tx_seq; /* Transmit sequence number (next) */ ++ uint8 tx_max; /* Maximum transmit sequence allowed */ ++ ++ uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN]; ++ uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ ++ uint16 nextlen; /* Next Read Len from last header */ ++ uint8 rx_seq; /* Receive sequence number (expected) */ ++ bool rxskip; /* Skip receive (awaiting NAK ACK) */ ++ ++ void *glomd; /* Packet containing glomming descriptor */ ++ void *glom; /* Packet chain for glommed superframe */ ++ uint glomerr; /* Glom packet read errors */ ++ ++ uint8 *rxbuf; /* Buffer for receiving control packets */ ++ uint rxblen; /* Allocated length of rxbuf */ ++ uint8 *rxctl; /* Aligned pointer into rxbuf */ ++ uint8 *databuf; /* Buffer for receiving big glom packet */ ++ uint8 *dataptr; /* Aligned pointer into databuf */ ++ uint rxlen; /* Length of valid data in buffer */ ++ ++ uint8 sdpcm_ver; /* Bus protocol reported by dongle */ ++ ++ bool intr; /* Use interrupts */ ++ bool poll; /* Use polling */ ++ bool ipend; /* Device interrupt is pending */ ++ bool intdis; /* Interrupts disabled by isr */ ++ uint intrcount; /* Count of device interrupt callbacks */ ++ uint lastintrs; /* Count as of last watchdog timer */ ++ uint spurious; /* Count of spurious interrupts */ ++ uint pollrate; /* Ticks between device polls */ ++ uint polltick; /* Tick counter */ ++ uint pollcnt; /* Count of active polls */ ++ ++#ifdef DHD_DEBUG ++ dhd_console_t console; /* Console output polling support */ ++ uint console_addr; /* Console address from shared struct */ ++#endif /* DHD_DEBUG */ ++ ++ uint regfails; /* Count of R_REG/W_REG failures */ ++ ++ uint clkstate; /* State of sd and backplane clock(s) */ ++ bool activity; /* Activity flag for clock down */ ++ int32 idletime; /* Control for activity timeout */ ++ int32 idlecount; /* Activity timeout counter */ ++ int32 idleclock; /* How to set bus driver when idle */ ++ int32 sd_divisor; /* Speed control to bus driver */ ++ int32 sd_mode; /* Mode control to bus driver */ ++ int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */ ++ bool use_rxchain; /* If dhd should use PKT chains */ ++ bool sleeping; /* Is SDIO bus sleeping? */ ++ uint rxflow_mode; /* Rx flow control mode */ ++ bool rxflow; /* Is rx flow control on */ ++ uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */ ++ bool alp_only; /* Don't use HT clock (ALP only) */ ++ /* Field to decide if rx of control frames happen in rxbuf or lb-pool */ ++ bool usebufpool; ++ ++#ifdef SDTEST ++ /* external loopback */ ++ bool ext_loop; ++ uint8 loopid; ++ ++ /* pktgen configuration */ ++ uint pktgen_freq; /* Ticks between bursts */ ++ uint pktgen_count; /* Packets to send each burst */ ++ uint pktgen_print; /* Bursts between count displays */ ++ uint pktgen_total; /* Stop after this many */ ++ uint pktgen_minlen; /* Minimum packet data len */ ++ uint pktgen_maxlen; /* Maximum packet data len */ ++ uint pktgen_mode; /* Configured mode: tx, rx, or echo */ ++ uint pktgen_stop; /* Number of tx failures causing stop */ ++ ++ /* active pktgen fields */ ++ uint pktgen_tick; /* Tick counter for bursts */ ++ uint pktgen_ptick; /* Burst counter for printing */ ++ uint pktgen_sent; /* Number of test packets generated */ ++ uint pktgen_rcvd; /* Number of test packets received */ ++ uint pktgen_prev_time; /* Time at which previous stats where printed */ ++ uint pktgen_prev_sent; /* Number of test packets generated when ++ * previous stats were printed ++ */ ++ uint pktgen_prev_rcvd; /* Number of test packets received when ++ * previous stats were printed ++ */ ++ uint pktgen_fail; /* Number of failed send attempts */ ++ uint16 pktgen_len; /* Length of next packet to send */ ++#define PKTGEN_RCV_IDLE (0) ++#define PKTGEN_RCV_ONGOING (1) ++ uint16 pktgen_rcv_state; /* receive state */ ++ uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */ ++#endif /* SDTEST */ ++ ++ /* Some additional counters */ ++ uint tx_sderrs; /* Count of tx attempts with sd errors */ ++ uint fcqueued; /* Tx packets that got queued */ ++ uint rxrtx; /* Count of rtx requests (NAK to dongle) */ ++ uint rx_toolong; /* Receive frames too long to receive */ ++ uint rxc_errors; /* SDIO errors when reading control frames */ ++ uint rx_hdrfail; /* SDIO errors on header reads */ ++ uint rx_badhdr; /* Bad received headers (roosync?) */ ++ uint rx_badseq; /* Mismatched rx sequence number */ ++ uint fc_rcvd; /* Number of flow-control events received */ ++ uint fc_xoff; /* Number which turned on flow-control */ ++ uint fc_xon; /* Number which turned off flow-control */ ++ uint rxglomfail; /* Failed deglom attempts */ ++ uint rxglomframes; /* Number of glom frames (superframes) */ ++ uint rxglompkts; /* Number of packets from glom frames */ ++ uint f2rxhdrs; /* Number of header reads */ ++ uint f2rxdata; /* Number of frame data reads */ ++ uint f2txdata; /* Number of f2 frame writes */ ++ uint f1regdata; /* Number of f1 register accesses */ ++ ++ uint8 *ctrl_frame_buf; ++ uint32 ctrl_frame_len; ++ bool ctrl_frame_stat; ++ uint32 rxint_mode; /* rx interrupt mode */ ++ bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram ++ * Available with socram rev 16 ++ * Remap region not DMA-able ++ */ ++ bool kso; ++ bool _slpauto; ++ bool _oobwakeup; ++ bool _srenab; ++ bool readframes; ++ bool reqbussleep; ++ uint32 resetinstr; ++ uint32 dongle_ram_base; ++#ifdef BCMSDIOH_TXGLOM ++ void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */ ++ uint16 glom_cnt; /* Number of pkts in the glom array */ ++ uint16 glom_total_len; /* Total length of pkts in glom array */ ++ bool glom_enable; /* Flag to indicate whether tx glom is enabled/disabled */ ++ uint8 glom_mode; /* Glom mode - 0-copy mode, 1 - Multi-descriptor mode */ ++ uint32 glomsize; /* Glom size limitation */ ++#endif ++} dhd_bus_t; ++ ++/* clkstate */ ++#define CLK_NONE 0 ++#define CLK_SDONLY 1 ++#define CLK_PENDING 2 /* Not used yet */ ++#define CLK_AVAIL 3 ++ ++#define DHD_NOPMU(dhd) (FALSE) ++ ++#ifdef DHD_DEBUG ++static int qcount[NUMPRIO]; ++static int tx_packets[NUMPRIO]; ++#endif /* DHD_DEBUG */ ++ ++/* Deferred transmit */ ++const uint dhd_deferred_tx = 1; ++ ++extern uint dhd_watchdog_ms; ++extern void dhd_os_wd_timer(void *bus, uint wdtick); ++ ++/* Tx/Rx bounds */ ++uint dhd_txbound; ++uint dhd_rxbound; ++uint dhd_txminmax = DHD_TXMINMAX; ++ ++/* override the RAM size if possible */ ++#define DONGLE_MIN_MEMSIZE (128 *1024) ++int dhd_dongle_memsize; ++ ++static bool dhd_doflow; ++static bool dhd_alignctl; ++ ++static bool sd1idle; ++ ++static bool retrydata; ++#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata) ++ ++#if defined(SDIO_CRC_ERROR_FIX) ++static uint watermark = 48; ++static uint mesbusyctrl = 80; ++#else ++static const uint watermark = 8; ++static const uint mesbusyctrl = 0; ++#endif ++static const uint firstread = DHD_FIRSTREAD; ++ ++#define HDATLEN (firstread - (SDPCM_HDRLEN)) ++ ++/* Retry count for register access failures */ ++static const uint retry_limit = 2; ++ ++/* Force even SD lengths (some host controllers mess up on odd bytes) */ ++static bool forcealign; ++ ++#define FW_TYPE_STA 0 ++#define FW_TYPE_APSTA 1 ++#define FW_TYPE_P2P 2 ++#define FW_TYPE_MFG 3 ++#define FW_TYPE_G 0 ++#define FW_TYPE_AG 1 ++ ++const static char *bcm40183b2_fw_name[] = { ++ "fw_bcm40183b2.bin", ++ "fw_bcm40183b2_apsta.bin", ++ "fw_bcm40183b2_p2p.bin", ++ "fw_bcm40183b2_mfg.bin" ++}; ++ ++const static char *bcm40183b2ag_fw_name[] = { ++ "fw_bcm40183b2_ag.bin", ++ "fw_bcm40183b2_ag_apsta.bin", ++ "fw_bcm40183b2_ag_p2p.bin", ++ "fw_bcm40183b2_ag_mfg.bin" ++}; ++ ++const static char *bcm40181a0_fw_name[] = { ++ "fw_bcm40181a0.bin", ++ "fw_bcm40181a0_apsta.bin", ++ "fw_bcm40181a0_p2p.bin", ++ "fw_bcm40181a0_mfg.bin" ++}; ++ ++const static char *bcm40181a2_fw_name[] = { ++ "fw_bcm40181a2.bin", ++ "fw_bcm40181a2_apsta.bin", ++ "fw_bcm40181a2_p2p.bin", ++ "fw_bcm40181a2_mfg.bin" ++}; ++ ++const static char *bcm43341b0ag_fw_name[] = { ++ "fw_bcm43341b0_ag.bin", ++ "fw_bcm43341b0_ag_apsta.bin", ++ "fw_bcm43341b0_ag_p2p.bin", ++ "fw_bcm43341b0_ag_mfg.bin" ++}; ++ ++const static char *bcm43241b4ag_fw_name[] = { ++ "fw_bcm43241b4_ag.bin", ++ "fw_bcm43241b4_ag_apsta.bin", ++ "fw_bcm43241b4_ag_p2p.bin", ++ "fw_bcm43241b4_ag_mfg.bin" ++}; ++ ++#define BCM4330B2_CHIP_REV 4 ++#define BCM43362A0_CHIP_REV 0 ++#define BCM43362A2_CHIP_REV 1 ++#define BCM43341B0_CHIP_REV 2 ++#define BCM43241B4_CHIP_REV 5 ++ ++#define ALIGNMENT 4 ++ ++#if defined(OOB_INTR_ONLY) && defined(HW_OOB) ++extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable); ++#endif ++ ++#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) ++#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD ++#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */ ++#define PKTALIGN(osh, p, len, align) \ ++ do { \ ++ uint datalign; \ ++ datalign = (uintptr)PKTDATA((osh), (p)); \ ++ datalign = ROUNDUP(datalign, (align)) - datalign; \ ++ ASSERT(datalign < (align)); \ ++ ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \ ++ if (datalign) \ ++ PKTPULL((osh), (p), datalign); \ ++ PKTSETLEN((osh), (p), (len)); \ ++ } while (0) ++ ++/* Limit on rounding up frames */ ++static const uint max_roundup = 512; ++ ++/* Try doing readahead */ ++static bool dhd_readahead; ++ ++ ++/* To check if there's window offered */ ++#define DATAOK(bus) \ ++ (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \ ++ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) ++ ++/* To check if there's window offered for ctrl frame */ ++#define TXCTLOK(bus) \ ++ (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \ ++ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) ++ ++/* Number of pkts available in dongle for data RX */ ++#define DATABUFCNT(bus) \ ++ ((uint8)(bus->tx_max - bus->tx_seq) - 1) ++ ++/* Macros to get register read/write status */ ++/* NOTE: these assume a local dhdsdio_bus_t *bus! */ ++#define R_SDREG(regvar, regaddr, retryvar) \ ++do { \ ++ retryvar = 0; \ ++ do { \ ++ regvar = R_REG(bus->dhd->osh, regaddr); \ ++ } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ ++ if (retryvar) { \ ++ bus->regfails += (retryvar-1); \ ++ if (retryvar > retry_limit) { \ ++ AP6211_ERR("%s: FAILED" #regvar "READ, LINE %d\n", \ ++ __FUNCTION__, __LINE__); \ ++ regvar = 0; \ ++ } \ ++ } \ ++} while (0) ++ ++#define W_SDREG(regval, regaddr, retryvar) \ ++do { \ ++ retryvar = 0; \ ++ do { \ ++ W_REG(bus->dhd->osh, regaddr, regval); \ ++ } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ ++ if (retryvar) { \ ++ bus->regfails += (retryvar-1); \ ++ if (retryvar > retry_limit) \ ++ AP6211_ERR("%s: FAILED REGISTER WRITE, LINE %d\n", \ ++ __FUNCTION__, __LINE__); \ ++ } \ ++} while (0) ++ ++#define BUS_WAKE(bus) \ ++ do { \ ++ bus->idlecount = 0; \ ++ if ((bus)->sleeping) \ ++ dhdsdio_bussleep((bus), FALSE); \ ++ } while (0); ++ ++/* ++ * pktavail interrupts from dongle to host can be managed in 3 different ways ++ * whenever there is a packet available in dongle to transmit to host. ++ * ++ * Mode 0: Dongle writes the software host mailbox and host is interrupted. ++ * Mode 1: (sdiod core rev >= 4) ++ * Device sets a new bit in the intstatus whenever there is a packet ++ * available in fifo. Host can't clear this specific status bit until all the ++ * packets are read from the FIFO. No need to ack dongle intstatus. ++ * Mode 2: (sdiod core rev >= 4) ++ * Device sets a bit in the intstatus, and host acks this by writing ++ * one to this bit. Dongle won't generate anymore packet interrupts ++ * until host reads all the packets from the dongle and reads a zero to ++ * figure that there are no more packets. No need to disable host ints. ++ * Need to ack the intstatus. ++ */ ++ ++#define SDIO_DEVICE_HMB_RXINT 0 /* default old way */ ++#define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */ ++#define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */ ++ ++ ++#define FRAME_AVAIL_MASK(bus) \ ++ ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL) ++ ++#define DHD_BUS SDIO_BUS ++ ++#define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus))) ++ ++#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) ++ ++#define GSPI_PR55150_BAILOUT ++ ++#ifdef SDTEST ++static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq); ++static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count); ++#endif ++ ++#ifdef DHD_DEBUG ++static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size); ++static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror); ++#endif /* DHD_DEBUG */ ++ ++static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap); ++static int dhdsdio_download_state(dhd_bus_t *bus, bool enter); ++ ++static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh); ++static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh); ++static void dhdsdio_disconnect(void *ptr); ++static bool dhdsdio_chipmatch(uint16 chipid); ++static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh, ++ void * regsva, uint16 devid); ++static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh); ++static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh); ++static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, ++ bool reset_flag); ++ ++static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size); ++static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, ++ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); ++static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, ++ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); ++#ifdef BCMSDIOH_TXGLOM ++static void dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, uint len); ++static void dhd_bcmsdh_glom_clear(dhd_bus_t *bus); ++#endif ++ ++static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh); ++static int _dhdsdio_download_firmware(dhd_bus_t *bus); ++ ++static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path); ++static int dhdsdio_download_nvram(dhd_bus_t *bus); ++#ifdef BCMEMBEDIMAGE ++static int dhdsdio_download_code_array(dhd_bus_t *bus); ++#endif ++static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep); ++static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok); ++static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus); ++ ++#ifdef WLMEDIA_HTSF ++#include ++extern uint32 dhd_get_htsf(void *dhd, int ifidx); ++#endif /* WLMEDIA_HTSF */ ++ ++static void ++dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size) ++{ ++ int32 min_size = DONGLE_MIN_MEMSIZE; ++ /* Restrict the memsize to user specified limit */ ++ AP6211_DEBUG("user: Restrict the dongle ram size to %d, min accepted %d\n", ++ dhd_dongle_memsize, min_size); ++ if ((dhd_dongle_memsize > min_size) && ++ (dhd_dongle_memsize < (int32)bus->orig_ramsize)) ++ bus->ramsize = dhd_dongle_memsize; ++} ++ ++static int ++dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address) ++{ ++ int err = 0; ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, ++ (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); ++ if (!err) ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, ++ (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); ++ if (!err) ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, ++ (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); ++ return err; ++} ++ ++ ++#ifdef USE_OOB_GPIO1 ++static int ++dhdsdio_oobwakeup_init(dhd_bus_t *bus) ++{ ++ uint32 val, addr, data; ++ ++ bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP); ++ ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); ++ data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); ++ ++ /* Set device for gpio1 wakeup */ ++ bcmsdh_reg_write(bus->sdh, addr, 4, 2); ++ val = bcmsdh_reg_read(bus->sdh, data, 4); ++ val |= CC_CHIPCTRL2_GPIO1_WAKEUP; ++ bcmsdh_reg_write(bus->sdh, data, 4, val); ++ ++ bus->_oobwakeup = TRUE; ++ ++ return 0; ++} ++#endif /* USE_OOB_GPIO1 */ ++ ++/* ++ * Query if FW is in SR mode ++ */ ++static bool ++dhdsdio_sr_cap(dhd_bus_t *bus) ++{ ++ bool cap = FALSE; ++ uint32 min = 0, core_capext, addr, data; ++ if (bus->sih->chip == BCM4324_CHIP_ID) { ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); ++ data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); ++ bcmsdh_reg_write(bus->sdh, addr, 4, 3); ++ core_capext = bcmsdh_reg_read(bus->sdh, data, 4); ++ } else if (bus->sih->chip == BCM4330_CHIP_ID || bus->sih->chip == BCM43362_CHIP_ID) { ++ core_capext = FALSE; ++ } else if (bus->sih->chip == BCM4335_CHIP_ID) { ++ core_capext = TRUE; ++ } else { ++ core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4); ++ core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK); ++ } ++ if (!(core_capext)) ++ return FALSE; ++ ++ if (bus->sih->chip == BCM4324_CHIP_ID) { ++ /* FIX: Should change to query SR control register instead */ ++ min = bcmsdh_reg_read(bus->sdh, MIN_RSRC_ADDR, 4); ++ if (min == MIN_RSRC_SR) ++ cap = TRUE; ++ } else if (bus->sih->chip == BCM4335_CHIP_ID) { ++ uint32 enabval = 0; ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); ++ data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); ++ bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3); ++ enabval = bcmsdh_reg_read(bus->sdh, data, 4); ++ ++ if (enabval) ++ cap = TRUE; ++ } else { ++ data = bcmsdh_reg_read(bus->sdh, ++ SI_ENUM_BASE + OFFSETOF(chipcregs_t, retention_ctl), 4); ++ if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0) ++ cap = TRUE; ++ } ++ ++ return cap; ++} ++ ++static int ++dhdsdio_srwar_init(dhd_bus_t *bus) ++{ ++ ++ bcmsdh_gpio_init(bus->sdh); ++ ++#ifdef USE_OOB_GPIO1 ++ dhdsdio_oobwakeup_init(bus); ++#endif ++ ++ ++ return 0; ++} ++ ++static int ++dhdsdio_sr_init(dhd_bus_t *bus) ++{ ++ uint8 val; ++ int err = 0; ++ ++ if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) ++ dhdsdio_srwar_init(bus); ++ ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); ++ val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT; ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, ++ 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err); ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); ++ ++ /* Add CMD14 Support */ ++ dhdsdio_devcap_set(bus, ++ (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT)); ++ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err); ++ ++ bus->_slpauto = dhd_slpauto ? TRUE : FALSE; ++ ++ bus->_srenab = TRUE; ++ ++ return 0; ++} ++ ++/* ++ * FIX: Be sure KSO bit is enabled ++ * Currently, it's defaulting to 0 which should be 1. ++ */ ++static int ++dhdsdio_clk_kso_init(dhd_bus_t *bus) ++{ ++ uint8 val; ++ int err = 0; ++ ++ /* set flag */ ++ bus->kso = TRUE; ++ ++ /* ++ * Enable KeepSdioOn (KSO) bit for normal operation ++ * Default is 0 (4334A0) so set it. Fixed in B0. ++ */ ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL); ++ if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { ++ val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err); ++ if (err) ++ AP6211_ERR("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err); ++ } ++ ++ return 0; ++} ++ ++#define KSO_DBG(x) ++#define MAX_KSO_ATTEMPTS 64 ++static int ++dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) ++{ ++ uint8 wr_val = 0, rd_val, cmp_val, bmask; ++ int err = 0; ++ int try_cnt = 0; ++ ++ KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"))); ++ ++ wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); ++ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); ++ ++ if (on) { ++ cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK; ++ bmask = cmp_val; ++ ++ msleep(3); ++ ++ } else { ++ /* Put device to sleep, turn off KSO */ ++ cmp_val = 0; ++ bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK; ++ } ++ ++ do { ++ rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); ++ if (((rd_val & bmask) == cmp_val) && !err) ++ break; ++ ++ KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err)); ++ OSL_DELAY(50); ++ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); ++ ++ } while (try_cnt++ < MAX_KSO_ATTEMPTS); ++ ++ ++ if (try_cnt > 1) { ++ KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n", ++ __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); ++ } ++ ++ if (try_cnt > MAX_KSO_ATTEMPTS) { ++ AP6211_ERR("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n", ++ __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err); ++ } ++ return err; ++} ++ ++static int ++dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on) ++{ ++ int err = 0; ++ ++ if (on == FALSE) { ++ ++ BUS_WAKE(bus); ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ AP6211_DEBUG("%s: KSO disable clk: 0x%x\n", __FUNCTION__, ++ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err)); ++ dhdsdio_clk_kso_enab(bus, FALSE); ++ } else { ++ AP6211_DEBUG("%s: KSO enable\n", __FUNCTION__); ++ ++ /* Make sure we have SD bus access */ ++ if (bus->clkstate == CLK_NONE) { ++ AP6211_DEBUG("%s: Request SD clk\n", __FUNCTION__); ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ } ++ ++ /* Double-write to be safe in case transition of AOS */ ++ dhdsdio_clk_kso_enab(bus, TRUE); ++ dhdsdio_clk_kso_enab(bus, TRUE); ++ OSL_DELAY(4000); ++ ++ /* Wait for device ready during transition to wake-up */ ++ SPINWAIT(((dhdsdio_sleepcsr_get(bus)) != ++ (SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | ++ SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), ++ (10000)); ++ ++ AP6211_DEBUG("%s: sleepcsr: 0x%x\n", __FUNCTION__, ++ dhdsdio_sleepcsr_get(bus)); ++ } ++ ++ bus->kso = on; ++ BCM_REFERENCE(err); ++ ++ return 0; ++} ++ ++static uint8 ++dhdsdio_sleepcsr_get(dhd_bus_t *bus) ++{ ++ int err = 0; ++ uint8 val = 0; ++ ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); ++ if (err) ++ AP6211_DEBUG("Failed to read SLEEPCSR: %d\n", err); ++ ++ return val; ++} ++ ++uint8 ++dhdsdio_devcap_get(dhd_bus_t *bus) ++{ ++ return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL); ++} ++ ++static int ++dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap) ++{ ++ int err = 0; ++ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err); ++ if (err) ++ AP6211_ERR("%s: devcap set err: 0x%x\n", __FUNCTION__, err); ++ ++ return 0; ++} ++ ++static int ++dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on) ++{ ++ int err = 0, retry; ++ uint8 val; ++ ++ retry = 0; ++ if (on == TRUE) { ++ /* Enter Sleep */ ++ ++ /* Be sure we request clk before going to sleep ++ * so we can wake-up with clk request already set ++ * else device can go back to sleep immediately ++ */ ++ if (!SLPAUTO_ENAB(bus)) ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ else { ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if ((val & SBSDIO_CSR_MASK) == 0) { ++ AP6211_DEBUG("%s: No clock before enter sleep:0x%x\n", ++ __FUNCTION__, val); ++ ++ /* Reset clock request */ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ SBSDIO_ALP_AVAIL_REQ, &err); ++ AP6211_DEBUG("%s: clock before sleep:0x%x\n", __FUNCTION__, ++ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err)); ++ } ++ } ++ ++ AP6211_DEBUG("%s: clk before sleep: 0x%x\n", __FUNCTION__, ++ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err)); ++#ifdef USE_CMD14 ++ err = bcmsdh_sleep(bus->sdh, TRUE); ++#else ++ err = dhdsdio_clk_kso_enab(bus, FALSE); ++ if (OOB_WAKEUP_ENAB(bus)) ++ err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */ ++#endif ++ } else { ++ /* Exit Sleep */ ++ /* Make sure we have SD bus access */ ++ if (bus->clkstate == CLK_NONE) { ++ AP6211_DEBUG("%s: Request SD clk\n", __FUNCTION__); ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ } ++ ++ if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) { ++ SPINWAIT((bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE), ++ GPIO_DEV_SRSTATE_TIMEOUT); ++ ++ if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) { ++ AP6211_ERR("ERROR: GPIO_DEV_SRSTATE still low!\n"); ++ } ++ } ++#ifdef USE_CMD14 ++ err = bcmsdh_sleep(bus->sdh, FALSE); ++ if (SLPAUTO_ENAB(bus) && (err != 0)) { ++ OSL_DELAY(10000); ++ AP6211_DEBUG("%s: Resync device sleep\n", __FUNCTION__); ++ ++ /* Toggle sleep to resync with host and device */ ++ err = bcmsdh_sleep(bus->sdh, TRUE); ++ OSL_DELAY(10000); ++ err = bcmsdh_sleep(bus->sdh, FALSE); ++ ++ if (err) { ++ OSL_DELAY(10000); ++ AP6211_ERR("%s: CMD14 exit failed again!\n", __FUNCTION__); ++ ++ /* Toggle sleep to resync with host and device */ ++ err = bcmsdh_sleep(bus->sdh, TRUE); ++ OSL_DELAY(10000); ++ err = bcmsdh_sleep(bus->sdh, FALSE); ++ if (err) { ++ AP6211_ERR("%s: CMD14 exit failed twice!\n", __FUNCTION__); ++ AP6211_ERR("%s: FATAL: Device non-response!\n", ++ __FUNCTION__); ++ err = 0; ++ } ++ } ++ } ++#else ++ if (OOB_WAKEUP_ENAB(bus)) ++ err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */ ++ ++ do { ++ err = dhdsdio_clk_kso_enab(bus, TRUE); ++ if (err) ++ OSL_DELAY(10000); ++ } while ((err != 0) && (++retry < 3)); ++ ++ if (err != 0) { ++ AP6211_ERR("ERROR: kso set failed retry: %d\n", retry); ++ err = 0; /* continue anyway */ ++ } ++#endif /* !USE_CMD14 */ ++ ++ if (err == 0) { ++ uint8 csr; ++ ++ /* Wait for device ready during transition to wake-up */ ++ SPINWAIT((((csr = dhdsdio_sleepcsr_get(bus)) & ++ SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) != ++ (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000)); ++ ++ AP6211_DEBUG("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr); ++ ++ if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) { ++ AP6211_ERR("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n", ++ __FUNCTION__, csr); ++ err = BCME_NODEVICE; ++ } ++ ++ SPINWAIT((((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) != ++ (SBSDIO_HT_AVAIL)), (10000)); ++ ++ } ++ } ++ ++ /* Update if successful */ ++ if (err == 0) ++ bus->kso = on ? FALSE : TRUE; ++ else { ++ AP6211_ERR("%s: Sleep request failed: on:%d err:%d\n", __FUNCTION__, on, err); ++ if (!on && retry > 2) ++ bus->kso = TRUE; ++ } ++ ++ return err; ++} ++ ++/* Turn backplane clock on or off */ ++static int ++dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) ++{ ++#define HT_AVAIL_ERROR_MAX 10 ++ static int ht_avail_error = 0; ++ int err; ++ uint8 clkctl, clkreq, devctl; ++ bcmsdh_info_t *sdh; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++#if defined(OOB_INTR_ONLY) ++ pendok = FALSE; ++#endif ++ clkctl = 0; ++ sdh = bus->sdh; ++ ++ ++ if (!KSO_ENAB(bus)) ++ return BCME_OK; ++ ++ if (SLPAUTO_ENAB(bus)) { ++ bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY); ++ return BCME_OK; ++ } ++ ++ if (on) { ++ /* Request HT Avail */ ++ clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; ++ ++ ++ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); ++ if (err) { ++ ht_avail_error++; ++ if (ht_avail_error < HT_AVAIL_ERROR_MAX) { ++ AP6211_ERR("%s: HT Avail request error: %d\n", __FUNCTION__, err); ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++ else if (ht_avail_error == HT_AVAIL_ERROR_MAX) { ++ dhd_os_send_hang_message(bus->dhd); ++ } ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ ++ return BCME_ERROR; ++ } else { ++ ht_avail_error = 0; ++ } ++ ++ if (pendok && ++ ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev == 9))) { ++ uint32 dummy, retries; ++ R_SDREG(dummy, &bus->regs->clockctlstatus, retries); ++ BCM_REFERENCE(dummy); ++ } ++ ++ /* Check current status */ ++ clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if (err) { ++ AP6211_ERR("%s: HT Avail read error: %d\n", __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ ++ /* Go to pending and await interrupt if appropriate */ ++ if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { ++ /* Allow only clock-available interrupt */ ++ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); ++ if (err) { ++ AP6211_ERR("%s: Devctl access error setting CA: %d\n", ++ __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ ++ devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); ++ AP6211_DEBUG("CLKCTL: set PENDING\n"); ++ bus->clkstate = CLK_PENDING; ++ return BCME_OK; ++ } else if (bus->clkstate == CLK_PENDING) { ++ /* Cancel CA-only interrupt filter */ ++ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); ++ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); ++ } ++ ++ /* Otherwise, wait here (polling) for HT Avail */ ++ if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { ++ SPINWAIT_SLEEP(sdioh_spinwait_sleep, ++ ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err)), ++ !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY); ++ } ++ if (err) { ++ AP6211_ERR("%s: HT Avail request error: %d\n", __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { ++ AP6211_ERR("%s: HT Avail timeout (%d): clkctl 0x%02x\n", ++ __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl); ++ return BCME_ERROR; ++ } ++ ++ /* Mark clock available */ ++ bus->clkstate = CLK_AVAIL; ++ AP6211_DEBUG("CLKCTL: turned ON\n"); ++ ++#if defined(DHD_DEBUG) ++ if (bus->alp_only == TRUE) { ++#if !defined(BCMLXSDMMC) ++ if (!SBSDIO_ALPONLY(clkctl)) { ++ AP6211_ERR("%s: HT Clock, when ALP Only\n", __FUNCTION__); ++ } ++#endif /* !defined(BCMLXSDMMC) */ ++ } else { ++ if (SBSDIO_ALPONLY(clkctl)) { ++ AP6211_ERR("%s: HT Clock should be on.\n", __FUNCTION__); ++ } ++ } ++#endif /* defined (DHD_DEBUG) */ ++ ++ bus->activity = TRUE; ++#ifdef DHD_USE_IDLECOUNT ++ bus->idlecount = 0; ++#endif /* DHD_USE_IDLECOUNT */ ++ } else { ++ clkreq = 0; ++ if (bus->clkstate == CLK_PENDING) { ++ /* Cancel CA-only interrupt filter */ ++ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); ++ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); ++ } ++ ++ bus->clkstate = CLK_SDONLY; ++ if (!SR_ENAB(bus)) { ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); ++ AP6211_DEBUG("CLKCTL: turned OFF\n"); ++ if (err) { ++ AP6211_ERR("%s: Failed access turning clock off: %d\n", ++ __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ } ++ } ++ return BCME_OK; ++} ++ ++/* Change idle/active SD state */ ++static int ++dhdsdio_sdclk(dhd_bus_t *bus, bool on) ++{ ++ int err; ++ int32 iovalue; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (on) { ++ if (bus->idleclock == DHD_IDLE_STOP) { ++ /* Turn on clock and restore mode */ ++ iovalue = 1; ++ err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, ++ &iovalue, sizeof(iovalue), TRUE); ++ if (err) { ++ AP6211_ERR("%s: error enabling sd_clock: %d\n", ++ __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ ++ iovalue = bus->sd_mode; ++ err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, ++ &iovalue, sizeof(iovalue), TRUE); ++ if (err) { ++ AP6211_ERR("%s: error changing sd_mode: %d\n", ++ __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ } else if (bus->idleclock != DHD_IDLE_ACTIVE) { ++ /* Restore clock speed */ ++ iovalue = bus->sd_divisor; ++ err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, ++ &iovalue, sizeof(iovalue), TRUE); ++ if (err) { ++ AP6211_ERR("%s: error restoring sd_divisor: %d\n", ++ __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ } ++ bus->clkstate = CLK_SDONLY; ++ } else { ++ /* Stop or slow the SD clock itself */ ++ if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) { ++ AP6211_DEBUG("%s: can't idle clock, divisor %d mode %d\n", ++ __FUNCTION__, bus->sd_divisor, bus->sd_mode); ++ return BCME_ERROR; ++ } ++ if (bus->idleclock == DHD_IDLE_STOP) { ++ if (sd1idle) { ++ /* Change to SD1 mode and turn off clock */ ++ iovalue = 1; ++ err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, ++ &iovalue, sizeof(iovalue), TRUE); ++ if (err) { ++ AP6211_ERR("%s: error changing sd_clock: %d\n", ++ __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ } ++ ++ iovalue = 0; ++ err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, ++ &iovalue, sizeof(iovalue), TRUE); ++ if (err) { ++ AP6211_ERR("%s: error disabling sd_clock: %d\n", ++ __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ } else if (bus->idleclock != DHD_IDLE_ACTIVE) { ++ /* Set divisor to idle value */ ++ iovalue = bus->idleclock; ++ err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, ++ &iovalue, sizeof(iovalue), TRUE); ++ if (err) { ++ AP6211_ERR("%s: error changing sd_divisor: %d\n", ++ __FUNCTION__, err); ++ return BCME_ERROR; ++ } ++ } ++ bus->clkstate = CLK_NONE; ++ } ++ ++ return BCME_OK; ++} ++ ++/* Transition SD and backplane clock readiness */ ++static int ++dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) ++{ ++ int ret = BCME_OK; ++#ifdef DHD_DEBUG ++ uint oldstate = bus->clkstate; ++#endif /* DHD_DEBUG */ ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ /* Early exit if we're already there */ ++ if (bus->clkstate == target) { ++ if (target == CLK_AVAIL) { ++ dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); ++ bus->activity = TRUE; ++#ifdef DHD_USE_IDLECOUNT ++ bus->idlecount = 0; ++#endif /* DHD_USE_IDLECOUNT */ ++ } ++ return ret; ++ } ++ ++ switch (target) { ++ case CLK_AVAIL: ++ /* Make sure SD clock is available */ ++ if (bus->clkstate == CLK_NONE) ++ dhdsdio_sdclk(bus, TRUE); ++ /* Now request HT Avail on the backplane */ ++ ret = dhdsdio_htclk(bus, TRUE, pendok); ++ if (ret == BCME_OK) { ++ dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); ++ bus->activity = TRUE; ++#ifdef DHD_USE_IDLECOUNT ++ bus->idlecount = 0; ++#endif /* DHD_USE_IDLECOUNT */ ++ } ++ break; ++ ++ case CLK_SDONLY: ++ /* Remove HT request, or bring up SD clock */ ++ if (bus->clkstate == CLK_NONE) ++ ret = dhdsdio_sdclk(bus, TRUE); ++ else if (bus->clkstate == CLK_AVAIL) ++ ret = dhdsdio_htclk(bus, FALSE, FALSE); ++ else ++ AP6211_DEBUG("dhdsdio_clkctl: request for %d -> %d\n", ++ bus->clkstate, target); ++ if (ret == BCME_OK) { ++ dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); ++ } ++ break; ++ ++ case CLK_NONE: ++ /* Make sure to remove HT request */ ++ if (bus->clkstate == CLK_AVAIL) ++ ret = dhdsdio_htclk(bus, FALSE, FALSE); ++ /* Now remove the SD clock */ ++ ret = dhdsdio_sdclk(bus, FALSE); ++#ifdef DHD_DEBUG ++ if (dhd_console_ms == 0) ++#endif /* DHD_DEBUG */ ++ if (bus->poll == 0) ++ dhd_os_wd_timer(bus->dhd, 0); ++ break; ++ } ++#ifdef DHD_DEBUG ++ AP6211_DEBUG("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate); ++#endif /* DHD_DEBUG */ ++ ++ return ret; ++} ++ ++static int ++dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) ++{ ++ int err = 0; ++ bcmsdh_info_t *sdh = bus->sdh; ++ sdpcmd_regs_t *regs = bus->regs; ++ uint retries = 0; ++ ++ AP6211_DEBUG("dhdsdio_bussleep: request %s (currently %s)\n", ++ (sleep ? "SLEEP" : "WAKE"), ++ (bus->sleeping ? "SLEEP" : "WAKE")); ++ ++ /* Done if we're already in the requested state */ ++ if (sleep == bus->sleeping) ++ return BCME_OK; ++ ++ /* Going to sleep: set the alarm and turn off the lights... */ ++ if (sleep) { ++ /* Don't sleep if something is pending */ ++ if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) ++ return BCME_BUSY; ++ ++ ++ if (!SLPAUTO_ENAB(bus)) { ++ /* Disable SDIO interrupts (no longer interested) */ ++ bcmsdh_intr_disable(bus->sdh); ++ ++ /* Make sure the controller has the bus up */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ /* Tell device to start using OOB wakeup */ ++ W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); ++ if (retries > retry_limit) ++ AP6211_ERR("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"); ++ ++ /* Turn off our contribution to the HT clock request */ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); ++ ++ /* Isolate the bus */ ++ if (bus->sih->chip != BCM4329_CHIP_ID && ++ bus->sih->chip != BCM4319_CHIP_ID) { ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, ++ SBSDIO_DEVCTL_PADS_ISO, NULL); ++ } ++ } else { ++ /* Leave interrupts enabled since device can exit sleep and ++ * interrupt host ++ */ ++ err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */); ++ } ++ ++ /* Change state */ ++ bus->sleeping = TRUE; ++ ++ } else { ++ /* Waking up: bus power up is ok, set local state */ ++ ++ if (!SLPAUTO_ENAB(bus)) { ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err); ++ ++ /* Force pad isolation off if possible (in case power never toggled) */ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL); ++ ++ ++ /* Make sure the controller has the bus up */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ /* Send misc interrupt to indicate OOB not needed */ ++ W_SDREG(0, ®s->tosbmailboxdata, retries); ++ if (retries <= retry_limit) ++ W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); ++ ++ if (retries > retry_limit) ++ AP6211_ERR("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"); ++ ++ /* Make sure we have SD bus access */ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ ++ /* Enable interrupts again */ ++ if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) { ++ bus->intdis = FALSE; ++ bcmsdh_intr_enable(bus->sdh); ++ } ++ } else { ++ err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */); ++ } ++ ++ if (err == 0) { ++ /* Change state */ ++ bus->sleeping = FALSE; ++ } ++ } ++ ++ return err; ++} ++ ++#if defined(OOB_INTR_ONLY) ++void ++dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) ++{ ++#if defined(HW_OOB) ++ bcmsdh_enable_hw_oob_intr(bus->sdh, enable); ++#else ++ sdpcmd_regs_t *regs = bus->regs; ++ uint retries = 0; ++ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ if (enable == TRUE) { ++ ++ /* Tell device to start using OOB wakeup */ ++ W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); ++ if (retries > retry_limit) ++ AP6211_ERR("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"); ++ ++ } else { ++ /* Send misc interrupt to indicate OOB not needed */ ++ W_SDREG(0, ®s->tosbmailboxdata, retries); ++ if (retries <= retry_limit) ++ W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); ++ } ++ ++ /* Turn off our contribution to the HT clock request */ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++#endif /* !defined(HW_OOB) */ ++} ++#endif ++ ++/* Writes a HW/SW header into the packet and sends it. */ ++/* Assumes: (a) header space already there, (b) caller holds lock */ ++static int ++dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_only) ++{ ++ int ret; ++ osl_t *osh; ++ uint8 *frame; ++ uint16 len, pad1 = 0; ++ uint32 swheader; ++ uint retries = 0; ++ bcmsdh_info_t *sdh; ++ void *new; ++ int i; ++ int pkt_cnt; ++#ifdef BCMSDIOH_TXGLOM ++ uint8 *frame_tmp; ++#endif ++#ifdef WLMEDIA_HTSF ++ char *p; ++ htsfts_t *htsf_ts; ++#endif ++ ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ sdh = bus->sdh; ++ osh = bus->dhd->osh; ++ ++ if (bus->dhd->dongle_reset) { ++ ret = BCME_NOTREADY; ++ goto done; ++ } ++ ++ frame = (uint8*)PKTDATA(osh, pkt); ++ ++#ifdef WLMEDIA_HTSF ++ if (PKTLEN(osh, pkt) >= 100) { ++ p = PKTDATA(osh, pkt); ++ htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12); ++ if (htsf_ts->magic == HTSFMAGIC) { ++ htsf_ts->c20 = get_cycles(); ++ htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0); ++ } ++ } ++#endif /* WLMEDIA_HTSF */ ++ ++ /* Add alignment padding, allocate new packet if needed */ ++ if (!((uintptr)frame & 1) && (pad1 = ((uintptr)frame % DHD_SDALIGN))) { ++ if (PKTHEADROOM(osh, pkt) < pad1) { ++ AP6211_ERR("%s: insufficient headroom %d for %d pad1\n", ++ __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1); ++ bus->dhd->tx_realloc++; ++ new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE); ++ if (!new) { ++ AP6211_ERR("%s: couldn't allocate new %d-byte packet\n", ++ __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN); ++ ret = BCME_NOMEM; ++ goto done; ++ } ++ ++ PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN); ++ bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt)); ++ if (free_pkt) ++ PKTFREE(osh, pkt, TRUE); ++ /* free the pkt if canned one is not used */ ++ free_pkt = TRUE; ++ pkt = new; ++ frame = (uint8*)PKTDATA(osh, pkt); ++ ASSERT(((uintptr)frame % DHD_SDALIGN) == 0); ++ pad1 = 0; ++ } else { ++ PKTPUSH(osh, pkt, pad1); ++ frame = (uint8*)PKTDATA(osh, pkt); ++ ++ ASSERT((pad1 + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt)); ++ bzero(frame, pad1 + SDPCM_HDRLEN); ++ } ++ } ++ ASSERT(pad1 < DHD_SDALIGN); ++ ++ /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ ++ len = (uint16)PKTLEN(osh, pkt); ++ *(uint16*)frame = htol16(len); ++ *(((uint16*)frame) + 1) = htol16(~len); ++ ++#ifdef BCMSDIOH_TXGLOM ++ if (bus->glom_enable) { ++ uint32 hwheader1 = 0, hwheader2 = 0, act_len = len; ++ ++ /* Software tag: channel, sequence number, data offset */ ++ swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | ++ ((bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP) | ++ (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); ++ htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); ++ htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + sizeof(swheader)); ++ ++ if (queue_only) { ++ if (forcealign && (len & (ALIGNMENT - 1))) ++ len = ROUNDUP(len, ALIGNMENT); ++ /* Hardware extention tag */ ++ /* 2byte frame length, 1byte-, 1byte frame flag, ++ * 2byte-hdrlength, 2byte padlenght ++ */ ++ hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (0 << 24); ++ hwheader2 = (len - act_len) << 16; ++ htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); ++ htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); ++ /* Post the frame pointer to sdio glom array */ ++ dhd_bcmsdh_glom_post(bus, frame, len); ++ /* Save the pkt pointer in bus glom array */ ++ bus->glom_pkt_arr[bus->glom_cnt] = pkt; ++ bus->glom_total_len += len; ++ bus->glom_cnt++; ++ return BCME_OK; ++ } else { ++ /* Raise len to next SDIO block to eliminate tail command */ ++ if (bus->roundup && bus->blocksize && ++ ((bus->glom_total_len + len) > bus->blocksize)) { ++ uint16 pad2 = bus->blocksize - ++ ((bus->glom_total_len + len) % bus->blocksize); ++ if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) { ++ len += pad2; ++ } else { ++ } ++ } else if ((bus->glom_total_len + len) % DHD_SDALIGN) { ++ len += DHD_SDALIGN ++ - ((bus->glom_total_len + len) % DHD_SDALIGN); ++ } ++ if (forcealign && (len & (ALIGNMENT - 1))) { ++ len = ROUNDUP(len, ALIGNMENT); ++ } ++ ++ /* Hardware extention tag */ ++ /* 2byte frame length, 1byte-, 1byte frame flag, ++ * 2byte-hdrlength, 2byte padlenght ++ */ ++ hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (1 << 24); ++ hwheader2 = (len - act_len) << 16; ++ htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); ++ htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); ++ ++ /* Post the frame pointer to sdio glom array */ ++ dhd_bcmsdh_glom_post(bus, frame, len); ++ /* Save the pkt pointer in bus glom array */ ++ bus->glom_pkt_arr[bus->glom_cnt] = pkt; ++ bus->glom_cnt++; ++ bus->glom_total_len += len; ++ ++ /* Update the total length on the first pkt */ ++ frame_tmp = (uint8*)PKTDATA(osh, bus->glom_pkt_arr[0]); ++ *(uint16*)frame_tmp = htol16(bus->glom_total_len); ++ *(((uint16*)frame_tmp) + 1) = htol16(~bus->glom_total_len); ++ } ++ } else ++#endif /* BCMSDIOH_TXGLOM */ ++ { ++ /* Software tag: channel, sequence number, data offset */ ++ swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq | ++ (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); ++ htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); ++ htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); ++ ++#ifdef DHD_DEBUG ++ if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) { ++ tx_packets[PKTPRIO(pkt)]++; ++ } ++ if (DHD_BYTES_ON() && ++ (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) || ++ (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) { ++ prhex("Tx Frame", frame, len); ++ } else if (DHD_HDRS_ON()) { ++ prhex("TxHdr", frame, MIN(len, 16)); ++ } ++#endif ++ ++ /* Raise len to next SDIO block to eliminate tail command */ ++ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { ++ uint16 pad2 = bus->blocksize - (len % bus->blocksize); ++ if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) ++#ifdef NOTUSED ++ if (pad2 <= PKTTAILROOM(osh, pkt)) ++#endif /* NOTUSED */ ++ len += pad2; ++ } else if (len % DHD_SDALIGN) { ++ len += DHD_SDALIGN - (len % DHD_SDALIGN); ++ } ++ ++ /* Some controllers have trouble with odd bytes -- round to even */ ++ if (forcealign && (len & (ALIGNMENT - 1))) { ++#ifdef NOTUSED ++ if (PKTTAILROOM(osh, pkt)) ++#endif ++ len = ROUNDUP(len, ALIGNMENT); ++#ifdef NOTUSED ++ else ++ AP6211_DEBUG("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len); ++#endif ++ } ++ } ++ ++ do { ++ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ frame, len, pkt, NULL, NULL); ++ bus->f2txdata++; ++ ASSERT(ret != BCME_PENDING); ++ ++ if (ret == BCME_NODEVICE) { ++ AP6211_ERR("%s: Device asleep already\n", __FUNCTION__); ++ } else if (ret < 0) { ++ /* On failure, abort the command and terminate the frame */ ++ AP6211_ERR("%s: sdio error %d, abort command and terminate frame.\n", ++ __FUNCTION__, ret); ++ bus->tx_sderrs++; ++ ++ bcmsdh_abort(sdh, SDIO_FUNC_2); ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, ++ SFC_WF_TERM, NULL); ++ bus->f1regdata++; ++ ++ for (i = 0; i < 3; i++) { ++ uint8 hi, lo; ++ hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCHI, NULL); ++ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCLO, NULL); ++ bus->f1regdata += 2; ++ if ((hi == 0) && (lo == 0)) ++ break; ++ } ++ } ++ if (ret == 0) { ++#ifdef BCMSDIOH_TXGLOM ++ if (bus->glom_enable) { ++ bus->tx_seq = (bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP; ++ } else ++#endif ++ { ++ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; ++ } ++ } ++ } while ((ret < 0) && retrydata && retries++ < TXRETRIES); ++ ++done: ++ ++#ifdef BCMSDIOH_TXGLOM ++ if (bus->glom_enable) { ++ dhd_bcmsdh_glom_clear(bus); ++ pkt_cnt = bus->glom_cnt; ++ } else ++#endif ++ { ++ pkt_cnt = 1; ++ } ++ /* restore pkt buffer pointer before calling tx complete routine */ ++ while (pkt_cnt) { ++#ifdef BCMSDIOH_TXGLOM ++ uint32 doff; ++ if (bus->glom_enable) { ++ pkt = bus->glom_pkt_arr[bus->glom_cnt - pkt_cnt]; ++ frame = (uint8*)PKTDATA(osh, pkt); ++ doff = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); ++ doff = (doff & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT; ++ PKTPULL(osh, pkt, doff); ++ } else ++#endif ++ { ++ PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1); ++ } ++#ifdef PROP_TXSTATUS ++ if (bus->dhd->wlfc_state) { ++ dhd_os_sdunlock(bus->dhd); ++ dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0, FALSE); ++ dhd_os_sdlock(bus->dhd); ++ } else { ++#endif /* PROP_TXSTATUS */ ++#ifdef SDTEST ++ if (chan != SDPCM_TEST_CHANNEL) { ++ dhd_txcomplete(bus->dhd, pkt, ret != 0); ++ } ++#else /* SDTEST */ ++ dhd_txcomplete(bus->dhd, pkt, ret != 0); ++#endif /* SDTEST */ ++ if (free_pkt) ++ PKTFREE(osh, pkt, TRUE); ++ ++#ifdef PROP_TXSTATUS ++ } ++#endif ++ pkt_cnt--; ++ } ++ ++#ifdef BCMSDIOH_TXGLOM ++ /* Reset the glom array */ ++ if (bus->glom_enable) { ++ bus->glom_cnt = 0; ++ bus->glom_total_len = 0; ++ } ++#endif ++ return ret; ++} ++ ++int ++dhd_bus_txdata(struct dhd_bus *bus, void *pkt, bool wlfc_locked) ++{ ++ int ret = BCME_ERROR; ++ osl_t *osh; ++ uint datalen, prec; ++#ifdef DHD_TX_DUMP ++ uint8 *dump_data; ++ uint16 protocol; ++#ifdef DHD_TX_FULL_DUMP ++ int i; ++#endif /* DHD_TX_FULL_DUMP */ ++#endif /* DHD_TX_DUMP */ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ osh = bus->dhd->osh; ++ datalen = PKTLEN(osh, pkt); ++ ++#ifdef SDTEST ++ /* Push the test header if doing loopback */ ++ if (bus->ext_loop) { ++ uint8* data; ++ PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN); ++ data = PKTDATA(osh, pkt); ++ *data++ = SDPCM_TEST_ECHOREQ; ++ *data++ = (uint8)bus->loopid++; ++ *data++ = (datalen >> 0); ++ *data++ = (datalen >> 8); ++ datalen += SDPCM_TEST_HDRLEN; ++ } ++#endif /* SDTEST */ ++ ++#ifdef DHD_TX_DUMP ++ dump_data = PKTDATA(osh, pkt); ++ dump_data += 4; /* skip 4 bytes header */ ++ protocol = (dump_data[12] << 8) | dump_data[13]; ++#ifdef DHD_TX_FULL_DUMP ++ AP6211_DEBUG("TX DUMP\n"); ++ ++ for (i = 0; i < (datalen - 4); i++) { ++ DHD_CONT("%02X ", dump_data[i]); ++ if ((i & 15) == 15) ++ DHD_CONT("\n"); ++ } ++ AP6211_DEBUG("\n"); ++ ++#endif /* DHD_TX_FULL_DUMP */ ++ if (protocol == ETHER_TYPE_802_1X) { ++ AP6211_DEBUG("ETHER_TYPE_802_1X: ver %d, type %d, replay %d\n", ++ dump_data[14], dump_data[15], dump_data[30]); ++ } ++#endif /* DHD_TX_DUMP */ ++ ++ /* Add space for the header */ ++ PKTPUSH(osh, pkt, SDPCM_HDRLEN); ++ ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2)); ++ ++ prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK)); ++#ifndef DHDTHREAD ++ /* Lock: we're about to use shared data/code (and SDIO) */ ++ dhd_os_sdlock(bus->dhd); ++#endif /* DHDTHREAD */ ++ ++ /* Check for existing queue, current flow-control, pending event, or pending clock */ ++ if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched || ++ (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) || ++ (bus->clkstate != CLK_AVAIL)) { ++ AP6211_DEBUG("%s: deferring pktq len %d\n", __FUNCTION__, ++ pktq_len(&bus->txq)); ++ bus->fcqueued++; ++ ++ /* Priority based enq */ ++ dhd_os_sdlock_txq(bus->dhd); ++ if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) { ++ PKTPULL(osh, pkt, SDPCM_HDRLEN); ++#ifndef DHDTHREAD ++ /* Need to also release txqlock before releasing sdlock. ++ * This thread still has txqlock and releases sdlock. ++ * Deadlock happens when dpc() grabs sdlock first then ++ * attempts to grab txqlock. ++ */ ++ dhd_os_sdunlock_txq(bus->dhd); ++ dhd_os_sdunlock(bus->dhd); ++#endif ++#ifdef PROP_TXSTATUS ++ if (bus->dhd->wlfc_state) ++ dhd_wlfc_txcomplete(bus->dhd, pkt, FALSE, wlfc_locked); ++ else ++#endif ++ dhd_txcomplete(bus->dhd, pkt, FALSE); ++#ifndef DHDTHREAD ++ dhd_os_sdlock(bus->dhd); ++ dhd_os_sdlock_txq(bus->dhd); ++#endif ++#ifdef PROP_TXSTATUS ++ /* let the caller decide whether to free the packet */ ++ if (!bus->dhd->wlfc_state) ++#endif ++ PKTFREE(osh, pkt, TRUE); ++ ret = BCME_NORESOURCE; ++ } ++ else ++ ret = BCME_OK; ++ dhd_os_sdunlock_txq(bus->dhd); ++ ++ if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow) ++ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); ++ ++#ifdef DHD_DEBUG ++ if (pktq_plen(&bus->txq, prec) > qcount[prec]) ++ qcount[prec] = pktq_plen(&bus->txq, prec); ++#endif ++ /* Schedule DPC if needed to send queued packet(s) */ ++ if (dhd_deferred_tx && !bus->dpc_sched) { ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ } ++ } else { ++#ifdef DHDTHREAD ++ /* Lock: we're about to use shared data/code (and SDIO) */ ++ dhd_os_sdlock(bus->dhd); ++#endif /* DHDTHREAD */ ++ ++ /* Otherwise, send it now */ ++ BUS_WAKE(bus); ++ /* Make sure back plane ht clk is on, no pending allowed */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); ++#ifndef SDTEST ++ ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE); ++#else ++ ret = dhdsdio_txpkt(bus, pkt, ++ (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE, FALSE); ++#endif ++ if (ret) ++ bus->dhd->tx_errors++; ++ else ++ bus->dhd->dstats.tx_bytes += datalen; ++ ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { ++ bus->activity = FALSE; ++ dhdsdio_clkctl(bus, CLK_NONE, TRUE); ++ } ++ ++#ifdef DHDTHREAD ++ dhd_os_sdunlock(bus->dhd); ++#endif /* DHDTHREAD */ ++ } ++ ++#ifndef DHDTHREAD ++ dhd_os_sdunlock(bus->dhd); ++#endif /* DHDTHREAD */ ++ ++ return ret; ++} ++ ++static uint ++dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) ++{ ++ void *pkt; ++ uint32 intstatus = 0; ++ uint retries = 0; ++ int ret = 0, prec_out; ++ uint cnt = 0; ++ uint datalen; ++ uint8 tx_prec_map; ++#ifdef BCMSDIOH_TXGLOM ++ uint i; ++ uint8 glom_cnt; ++#endif ++ ++ dhd_pub_t *dhd = bus->dhd; ++ sdpcmd_regs_t *regs = bus->regs; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (!KSO_ENAB(bus)) { ++ AP6211_DEBUG("%s: Device asleep\n", __FUNCTION__); ++ return BCME_NODEVICE; ++ } ++ ++ tx_prec_map = ~bus->flowcontrol; ++ ++ /* Send frames until the limit or some other event */ ++ for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) { ++#ifdef BCMSDIOH_TXGLOM ++ if (bus->glom_enable) { ++ glom_cnt = MIN(DATABUFCNT(bus), bus->glomsize); ++ glom_cnt = MIN(glom_cnt, pktq_mlen(&bus->txq, tx_prec_map)); ++ glom_cnt = MIN(glom_cnt, maxframes-cnt); ++ ++ /* Limiting the size to 2pkts in case of copy */ ++ if (bus->glom_mode == SDPCM_TXGLOM_CPY) ++ glom_cnt = MIN(glom_cnt, 5); ++ ++ if (glom_cnt == 0) ++ break; ++ datalen = 0; ++ for (i = 0; i < glom_cnt; i++) { ++ dhd_os_sdlock_txq(bus->dhd); ++ if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) { ++ /* This case should not happen */ ++ AP6211_DEBUG("No pkts in the queue for glomming\n"); ++ dhd_os_sdunlock_txq(bus->dhd); ++ break; ++ } ++ dhd_os_sdunlock_txq(bus->dhd); ++ ++ datalen += (PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN); ++#ifndef SDTEST ++ ret = dhdsdio_txpkt(bus, ++ pkt, ++ SDPCM_DATA_CHANNEL, ++ TRUE, ++ (i == (glom_cnt-1))? FALSE: TRUE); ++#else ++ ret = dhdsdio_txpkt(bus, ++ pkt, ++ (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), ++ TRUE, ++ (i == (glom_cnt-1))? FALSE: TRUE); ++#endif ++ } ++ cnt += i-1; ++ } else ++#endif /* BCMSDIOH_TXGLOM */ ++ { ++ dhd_os_sdlock_txq(bus->dhd); ++ if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) { ++ dhd_os_sdunlock_txq(bus->dhd); ++ break; ++ } ++ dhd_os_sdunlock_txq(bus->dhd); ++ datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN; ++ ++#ifndef SDTEST ++ ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE); ++#else ++ ret = dhdsdio_txpkt(bus, ++ pkt, ++ (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), ++ TRUE, ++ FALSE); ++#endif ++ } ++ ++ if (ret) ++ bus->dhd->tx_errors++; ++ else ++ bus->dhd->dstats.tx_bytes += datalen; ++ ++ /* In poll mode, need to check for other events */ ++ if (!bus->intr && cnt) ++ { ++ /* Check device status, signal pending interrupt */ ++ R_SDREG(intstatus, ®s->intstatus, retries); ++ bus->f2txdata++; ++ if (bcmsdh_regfail(bus->sdh)) ++ break; ++ if (intstatus & bus->hostintmask) ++ bus->ipend = TRUE; ++ } ++ } ++ ++ /* Deflow-control stack if needed */ ++ if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) && ++ dhd->txoff && (pktq_len(&bus->txq) < FCLOW)) ++ dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); ++ ++ return cnt; ++} ++ ++int ++dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) ++{ ++ uint8 *frame; ++ uint16 len; ++ uint32 swheader; ++ uint retries = 0; ++ bcmsdh_info_t *sdh = bus->sdh; ++ uint8 doff = 0; ++ int ret = -1; ++ int i; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (bus->dhd->dongle_reset) ++ return -EIO; ++ ++ /* Back the pointer to make a room for bus header */ ++ frame = msg - SDPCM_HDRLEN; ++ len = (msglen += SDPCM_HDRLEN); ++ ++ /* Add alignment padding (optional for ctl frames) */ ++ if (dhd_alignctl) { ++ if ((doff = ((uintptr)frame % DHD_SDALIGN))) { ++ frame -= doff; ++ len += doff; ++ msglen += doff; ++ bzero(frame, doff + SDPCM_HDRLEN); ++ } ++ ASSERT(doff < DHD_SDALIGN); ++ } ++ doff += SDPCM_HDRLEN; ++ ++ /* Round send length to next SDIO block */ ++ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { ++ uint16 pad = bus->blocksize - (len % bus->blocksize); ++ if ((pad <= bus->roundup) && (pad < bus->blocksize)) ++ len += pad; ++ } else if (len % DHD_SDALIGN) { ++ len += DHD_SDALIGN - (len % DHD_SDALIGN); ++ } ++ ++ /* Satisfy length-alignment requirements */ ++ if (forcealign && (len & (ALIGNMENT - 1))) ++ len = ROUNDUP(len, ALIGNMENT); ++ ++ ASSERT(ISALIGNED((uintptr)frame, 2)); ++ ++ ++ /* Need to lock here to protect txseq and SDIO tx calls */ ++ dhd_os_sdlock(bus->dhd); ++ ++ BUS_WAKE(bus); ++ ++ /* Make sure backplane clock is on */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ ++ *(uint16*)frame = htol16((uint16)msglen); ++ *(((uint16*)frame) + 1) = htol16(~msglen); ++ ++#ifdef BCMSDIOH_TXGLOM ++ if (bus->glom_enable) { ++ uint32 hwheader1, hwheader2; ++ /* Software tag: channel, sequence number, data offset */ ++ swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) ++ | bus->tx_seq ++ | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); ++ htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); ++ htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN ++ + SDPCM_HWEXT_LEN + sizeof(swheader)); ++ ++ hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24); ++ hwheader2 = (len - (msglen)) << 16; ++ htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); ++ htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); ++ ++ *(uint16*)frame = htol16(len); ++ *(((uint16*)frame) + 1) = htol16(~(len)); ++ } else ++#endif /* BCMSDIOH_TXGLOM */ ++ { ++ /* Software tag: channel, sequence number, data offset */ ++ swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) ++ | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); ++ htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); ++ htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); ++ } ++ if (!TXCTLOK(bus)) { ++ AP6211_DEBUG("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n", ++ __FUNCTION__, bus->tx_max, bus->tx_seq); ++ bus->ctrl_frame_stat = TRUE; ++ /* Send from dpc */ ++ bus->ctrl_frame_buf = frame; ++ bus->ctrl_frame_len = len; ++ ++ if (!bus->dpc_sched) { ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ } ++ if (bus->ctrl_frame_stat) { ++ dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat); ++ } ++ ++ if (bus->ctrl_frame_stat == FALSE) { ++ AP6211_DEBUG("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__); ++ ret = 0; ++ } else { ++ bus->dhd->txcnt_timeout++; ++ if (!bus->dhd->hang_was_sent) { ++ AP6211_DEBUG("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n", ++ __FUNCTION__, bus->dhd->txcnt_timeout); ++ } ++ ret = -1; ++ bus->ctrl_frame_stat = FALSE; ++ goto done; ++ } ++ } ++ ++ bus->dhd->txcnt_timeout = 0; ++ ++ if (ret == -1) { ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_CTL_ON()) { ++ prhex("Tx Frame", frame, len); ++ } else if (DHD_HDRS_ON()) { ++ prhex("TxHdr", frame, MIN(len, 16)); ++ } ++#endif ++ ++ do { ++ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ frame, len, NULL, NULL, NULL); ++ ASSERT(ret != BCME_PENDING); ++ ++ if (ret == BCME_NODEVICE) { ++ AP6211_DEBUG("%s: Device asleep already\n", __FUNCTION__); ++ } else if (ret < 0) { ++ /* On failure, abort the command and terminate the frame */ ++ AP6211_DEBUG("%s: sdio error %d, abort command and terminate frame.\n", ++ __FUNCTION__, ret); ++ bus->tx_sderrs++; ++ ++ bcmsdh_abort(sdh, SDIO_FUNC_2); ++ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, ++ SFC_WF_TERM, NULL); ++ bus->f1regdata++; ++ ++ for (i = 0; i < 3; i++) { ++ uint8 hi, lo; ++ hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCHI, NULL); ++ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCLO, NULL); ++ bus->f1regdata += 2; ++ if ((hi == 0) && (lo == 0)) ++ break; ++ } ++ } ++ if (ret == 0) { ++ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; ++ } ++ } while ((ret < 0) && retries++ < TXRETRIES); ++ } ++ ++done: ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { ++ bus->activity = FALSE; ++ dhdsdio_clkctl(bus, CLK_NONE, TRUE); ++ } ++ ++ dhd_os_sdunlock(bus->dhd); ++ ++ if (ret) ++ bus->dhd->tx_ctlerrs++; ++ else ++ bus->dhd->tx_ctlpkts++; ++ ++ if (bus->dhd->txcnt_timeout >= MAX_CNTL_TIMEOUT) ++ return -ETIMEDOUT; ++ ++ return ret ? -EIO : 0; ++} ++ ++int ++dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) ++{ ++ int timeleft; ++ uint rxlen = 0; ++ bool pending; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (bus->dhd->dongle_reset) ++ return -EIO; ++ ++ /* Wait until control frame is available */ ++ timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending); ++ ++ dhd_os_sdlock(bus->dhd); ++ rxlen = bus->rxlen; ++ bcopy(bus->rxctl, msg, MIN(msglen, rxlen)); ++ bus->rxlen = 0; ++ dhd_os_sdunlock(bus->dhd); ++ ++ if (rxlen) { ++ AP6211_DEBUG("%s: resumed on rxctl frame, got %d expected %d\n", ++ __FUNCTION__, rxlen, msglen); ++ } else if (timeleft == 0) { ++#ifdef DHD_DEBUG ++ uint32 status, retry = 0; ++ R_SDREG(status, &bus->regs->intstatus, retry); ++ AP6211_DEBUG("%s: resumed on timeout, INT status=0x%08X\n", ++ __FUNCTION__, status); ++#else ++ AP6211_DEBUG("%s: resumed on timeout\n", __FUNCTION__); ++#endif /* DHD_DEBUG */ ++#ifdef DHD_DEBUG ++ dhd_os_sdlock(bus->dhd); ++ dhdsdio_checkdied(bus, NULL, 0); ++ dhd_os_sdunlock(bus->dhd); ++#endif /* DHD_DEBUG */ ++ } else if (pending == TRUE) { ++ /* signal pending */ ++ AP6211_DEBUG("%s: signal pending\n", __FUNCTION__); ++ return -EINTR; ++ } else { ++ AP6211_DEBUG("%s: resumed for unknown reason?\n", __FUNCTION__); ++#ifdef DHD_DEBUG ++ dhd_os_sdlock(bus->dhd); ++ dhdsdio_checkdied(bus, NULL, 0); ++ dhd_os_sdunlock(bus->dhd); ++#endif /* DHD_DEBUG */ ++ } ++ if (timeleft == 0) { ++ bus->dhd->rxcnt_timeout++; ++ AP6211_DEBUG("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout); ++ } ++ else ++ bus->dhd->rxcnt_timeout = 0; ++ ++ if (rxlen) ++ bus->dhd->rx_ctlpkts++; ++ else ++ bus->dhd->rx_ctlerrs++; ++ ++ if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TIMEOUT) ++ return -ETIMEDOUT; ++ ++ if (bus->dhd->dongle_trap_occured) ++ return -EREMOTEIO; ++ ++ return rxlen ? (int)rxlen : -EIO; ++} ++ ++/* IOVar table */ ++enum { ++ IOV_INTR = 1, ++ IOV_POLLRATE, ++ IOV_SDREG, ++ IOV_SBREG, ++ IOV_SDCIS, ++ IOV_MEMBYTES, ++ IOV_MEMSIZE, ++#ifdef DHD_DEBUG ++ IOV_CHECKDIED, ++ IOV_SERIALCONS, ++#endif /* DHD_DEBUG */ ++ IOV_SET_DOWNLOAD_STATE, ++ IOV_SOCRAM_STATE, ++ IOV_FORCEEVEN, ++ IOV_SDIOD_DRIVE, ++ IOV_READAHEAD, ++ IOV_SDRXCHAIN, ++ IOV_ALIGNCTL, ++ IOV_SDALIGN, ++ IOV_DEVRESET, ++ IOV_CPU, ++#if defined(SDIO_CRC_ERROR_FIX) ++ IOV_WATERMARK, ++ IOV_MESBUSYCTRL, ++#endif /* SDIO_CRC_ERROR_FIX */ ++#ifdef SDTEST ++ IOV_PKTGEN, ++ IOV_EXTLOOP, ++#endif /* SDTEST */ ++ IOV_SPROM, ++ IOV_TXBOUND, ++ IOV_RXBOUND, ++ IOV_TXMINMAX, ++ IOV_IDLETIME, ++ IOV_IDLECLOCK, ++ IOV_SD1IDLE, ++ IOV_SLEEP, ++ IOV_DONGLEISOLATION, ++ IOV_KSO, ++ IOV_DEVSLEEP, ++ IOV_DEVCAP, ++ IOV_VARS, ++#ifdef SOFTAP ++ IOV_FWPATH, ++#endif ++ IOV_TXGLOMSIZE, ++ IOV_TXGLOMMODE ++}; ++ ++const bcm_iovar_t dhdsdio_iovars[] = { ++ {"intr", IOV_INTR, 0, IOVT_BOOL, 0 }, ++ {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 }, ++ {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 }, ++ {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 }, ++ {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 }, ++ {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 }, ++ {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, ++ {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 }, ++ {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 }, ++ {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 }, ++ {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, ++ {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 }, ++ {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 }, ++ {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 }, ++ {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 }, ++ {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 }, ++ {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 }, ++#ifdef DHD_DEBUG ++ {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, ++ {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, ++ {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, ++ {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 }, ++ {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 }, ++ {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 }, ++ {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 }, ++ {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 }, ++#ifdef DHD_DEBUG ++ {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 }, ++ {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 }, ++#endif /* DHD_DEBUG */ ++#endif /* DHD_DEBUG */ ++#ifdef SDTEST ++ {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 }, ++ {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) }, ++#endif /* SDTEST */ ++#if defined(SDIO_CRC_ERROR_FIX) ++ {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 }, ++ {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 }, ++#endif /* SDIO_CRC_ERROR_FIX */ ++ {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 }, ++ {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 }, ++ {"kso", IOV_KSO, 0, IOVT_UINT32, 0 }, ++ {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 }, ++#ifdef SOFTAP ++ {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 }, ++#endif ++ {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 }, ++ {"txglommode", IOV_TXGLOMMODE, 0, IOVT_UINT32, 0 }, ++ {NULL, 0, 0, 0, 0 } ++}; ++ ++static void ++dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div) ++{ ++ uint q1, q2; ++ ++ if (!div) { ++ bcm_bprintf(strbuf, "%s N/A", desc); ++ } else { ++ q1 = num / div; ++ q2 = (100 * (num - (q1 * div))) / div; ++ bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2); ++ } ++} ++ ++void ++dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ ++ bcm_bprintf(strbuf, "Bus SDIO structure:\n"); ++ bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n", ++ bus->hostintmask, bus->intstatus, bus->sdpcm_ver); ++ bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n", ++ bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip, ++ bus->rxlen, bus->rx_seq); ++ bcm_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n", ++ bus->intr, bus->intrcount, bus->lastintrs, bus->spurious); ++ bcm_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n", ++ bus->pollrate, bus->pollcnt, bus->regfails); ++ ++ bcm_bprintf(strbuf, "\nAdditional counters:\n"); ++ bcm_bprintf(strbuf, "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n", ++ bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong, ++ bus->rxc_errors); ++ bcm_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n", ++ bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq); ++ bcm_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n", ++ bus->fc_rcvd, bus->fc_xoff, bus->fc_xon); ++ bcm_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n", ++ bus->rxglomfail, bus->rxglomframes, bus->rxglompkts); ++ bcm_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs %d\n", ++ (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata, ++ bus->f2txdata, bus->f1regdata); ++ { ++ dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets, ++ (bus->f2rxhdrs + bus->f2rxdata)); ++ dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata); ++ dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets, ++ (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); ++ dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount); ++ bcm_bprintf(strbuf, "\n"); ++ ++ dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts), ++ bus->dhd->rx_packets); ++ dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes); ++ bcm_bprintf(strbuf, "\n"); ++ ++ dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata); ++ dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata); ++ dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets, ++ (bus->f2txdata + bus->f1regdata)); ++ dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount); ++ bcm_bprintf(strbuf, "\n"); ++ ++ dhd_dump_pct(strbuf, "Total: pkts/f2rw", ++ (bus->dhd->tx_packets + bus->dhd->rx_packets), ++ (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata)); ++ dhd_dump_pct(strbuf, ", pkts/f1sd", ++ (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata); ++ dhd_dump_pct(strbuf, ", pkts/sd", ++ (bus->dhd->tx_packets + bus->dhd->rx_packets), ++ (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); ++ dhd_dump_pct(strbuf, ", pkts/int", ++ (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount); ++ bcm_bprintf(strbuf, "\n\n"); ++ } ++ ++#ifdef SDTEST ++ if (bus->pktgen_count) { ++ bcm_bprintf(strbuf, "pktgen config and count:\n"); ++ bcm_bprintf(strbuf, "freq %d count %d print %d total %d min %d len %d\n", ++ bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print, ++ bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen); ++ bcm_bprintf(strbuf, "send attempts %d rcvd %d fail %d\n", ++ bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); ++ } ++#endif /* SDTEST */ ++#ifdef DHD_DEBUG ++ bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n", ++ bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not ")); ++ bcm_bprintf(strbuf, "blocksize %d roundup %d\n", bus->blocksize, bus->roundup); ++#endif /* DHD_DEBUG */ ++ bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n", ++ bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping); ++} ++ ++void ++dhd_bus_clearcounts(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus; ++ ++ bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0; ++ bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0; ++ bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0; ++ bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0; ++ bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0; ++ bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0; ++} ++ ++#ifdef SDTEST ++static int ++dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg) ++{ ++ dhd_pktgen_t pktgen; ++ ++ pktgen.version = DHD_PKTGEN_VERSION; ++ pktgen.freq = bus->pktgen_freq; ++ pktgen.count = bus->pktgen_count; ++ pktgen.print = bus->pktgen_print; ++ pktgen.total = bus->pktgen_total; ++ pktgen.minlen = bus->pktgen_minlen; ++ pktgen.maxlen = bus->pktgen_maxlen; ++ pktgen.numsent = bus->pktgen_sent; ++ pktgen.numrcvd = bus->pktgen_rcvd; ++ pktgen.numfail = bus->pktgen_fail; ++ pktgen.mode = bus->pktgen_mode; ++ pktgen.stop = bus->pktgen_stop; ++ ++ bcopy(&pktgen, arg, sizeof(pktgen)); ++ ++ return 0; ++} ++ ++static int ++dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg) ++{ ++ dhd_pktgen_t pktgen; ++ uint oldcnt, oldmode; ++ ++ bcopy(arg, &pktgen, sizeof(pktgen)); ++ if (pktgen.version != DHD_PKTGEN_VERSION) ++ return BCME_BADARG; ++ ++ oldcnt = bus->pktgen_count; ++ oldmode = bus->pktgen_mode; ++ ++ bus->pktgen_freq = pktgen.freq; ++ bus->pktgen_count = pktgen.count; ++ bus->pktgen_print = pktgen.print; ++ bus->pktgen_total = pktgen.total; ++ bus->pktgen_minlen = pktgen.minlen; ++ bus->pktgen_maxlen = pktgen.maxlen; ++ bus->pktgen_mode = pktgen.mode; ++ bus->pktgen_stop = pktgen.stop; ++ ++ bus->pktgen_tick = bus->pktgen_ptick = 0; ++ bus->pktgen_prev_time = jiffies; ++ bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen); ++ bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen); ++ ++ /* Clear counts for a new pktgen (mode change, or was stopped) */ ++ if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) { ++ bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0; ++ bus->pktgen_prev_rcvd = bus->pktgen_fail = 0; ++ } ++ ++ return 0; ++} ++#endif /* SDTEST */ ++ ++static void ++dhdsdio_devram_remap(dhd_bus_t *bus, bool val) ++{ ++ uint8 enable, protect, remap; ++ ++ si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); ++ remap = val ? TRUE : FALSE; ++ si_socdevram(bus->sih, TRUE, &enable, &protect, &remap); ++} ++ ++static int ++dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size) ++{ ++ int bcmerror = 0; ++ uint32 sdaddr; ++ uint dsize; ++ ++ /* In remap mode, adjust address beyond socram and redirect ++ * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize ++ * is not backplane accessible ++ */ ++ if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) { ++ address -= bus->orig_ramsize; ++ address += SOCDEVRAM_BP_ADDR; ++ } ++ ++ /* Determine initial transfer parameters */ ++ sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK; ++ if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK) ++ dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr); ++ else ++ dsize = size; ++ ++ /* Set the backplane window to include the start address */ ++ if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { ++ AP6211_ERR("%s: window change failed\n", __FUNCTION__); ++ goto xfer_done; ++ } ++ ++ /* Do the transfer(s) */ ++ while (size) { ++ AP6211_DEBUG("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n", ++ __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr, ++ (address & SBSDIO_SBWINDOW_MASK)); ++ if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) { ++ AP6211_ERR("%s: membytes transfer failed\n", __FUNCTION__); ++ break; ++ } ++ ++ /* Adjust for next transfer (if any) */ ++ if ((size -= dsize)) { ++ data += dsize; ++ address += dsize; ++ if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { ++ AP6211_ERR("%s: window change failed\n", __FUNCTION__); ++ break; ++ } ++ sdaddr = 0; ++ dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size); ++ } ++ ++ } ++ ++xfer_done: ++ /* Return the window to backplane enumeration space for core access */ ++ if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) { ++ AP6211_ERR("%s: FAILED to set window back to 0x%x\n", __FUNCTION__, ++ bcmsdh_cur_sbwad(bus->sdh)); ++ } ++ ++ return bcmerror; ++} ++ ++#ifdef DHD_DEBUG ++static int ++dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) ++{ ++ uint32 addr; ++ int rv, i; ++ uint32 shaddr = 0; ++ ++ shaddr = bus->dongle_ram_base + bus->ramsize - 4; ++ i = 0; ++ do { ++ /* Read last word in memory to determine address of sdpcm_shared structure */ ++ if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0) ++ return rv; ++ ++ addr = ltoh32(addr); ++ ++ AP6211_DEBUG("sdpcm_shared address 0x%08X\n", addr); ++ ++ /* ++ * Check if addr is valid. ++ * NVRAM length at the end of memory should have been overwritten. ++ */ ++ if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) { ++ if ((bus->srmemsize > 0) && (i++ == 0)) { ++ shaddr -= bus->srmemsize; ++ } else { ++ AP6211_ERR("%s: address (0x%08x) of sdpcm_shared invalid\n", ++ __FUNCTION__, addr); ++ return BCME_ERROR; ++ } ++ } else ++ break; ++ } while (i < 2); ++ ++ /* Read hndrte_shared structure */ ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0) ++ return rv; ++ ++ /* Endianness */ ++ sh->flags = ltoh32(sh->flags); ++ sh->trap_addr = ltoh32(sh->trap_addr); ++ sh->assert_exp_addr = ltoh32(sh->assert_exp_addr); ++ sh->assert_file_addr = ltoh32(sh->assert_file_addr); ++ sh->assert_line = ltoh32(sh->assert_line); ++ sh->console_addr = ltoh32(sh->console_addr); ++ sh->msgtrace_addr = ltoh32(sh->msgtrace_addr); ++ ++ if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1) ++ return BCME_OK; ++ ++ if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) { ++ AP6211_ERR("%s: sdpcm_shared version %d in dhd " ++ "is different than sdpcm_shared version %d in dongle\n", ++ __FUNCTION__, SDPCM_SHARED_VERSION, ++ sh->flags & SDPCM_SHARED_VERSION_MASK); ++ return BCME_ERROR; ++ } ++ ++ return BCME_OK; ++} ++ ++#define CONSOLE_LINE_MAX 192 ++ ++static int ++dhdsdio_readconsole(dhd_bus_t *bus) ++{ ++ dhd_console_t *c = &bus->console; ++ uint8 line[CONSOLE_LINE_MAX], ch; ++ uint32 n, idx, addr; ++ int rv; ++ ++ /* Don't do anything until FWREADY updates console address */ ++ if (bus->console_addr == 0) ++ return 0; ++ ++ if (!KSO_ENAB(bus)) ++ return 0; ++ ++ /* Read console log struct */ ++ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log); ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0) ++ return rv; ++ ++ /* Allocate console buffer (one time only) */ ++ if (c->buf == NULL) { ++ c->bufsize = ltoh32(c->log.buf_size); ++ if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL) ++ return BCME_NOMEM; ++ } ++ ++ idx = ltoh32(c->log.idx); ++ ++ /* Protect against corrupt value */ ++ if (idx > c->bufsize) ++ return BCME_ERROR; ++ ++ /* Skip reading the console buffer if the index pointer has not moved */ ++ if (idx == c->last) ++ return BCME_OK; ++ ++ /* Read the console buffer */ ++ addr = ltoh32(c->log.buf); ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0) ++ return rv; ++ ++ while (c->last != idx) { ++ for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { ++ if (c->last == idx) { ++ /* This would output a partial line. Instead, back up ++ * the buffer pointer and output this line next time around. ++ */ ++ if (c->last >= n) ++ c->last -= n; ++ else ++ c->last = c->bufsize - n; ++ goto break2; ++ } ++ ch = c->buf[c->last]; ++ c->last = (c->last + 1) % c->bufsize; ++ if (ch == '\n') ++ break; ++ line[n] = ch; ++ } ++ ++ if (n > 0) { ++ if (line[n - 1] == '\r') ++ n--; ++ line[n] = 0; ++ AP6211_DEBUG("CONSOLE: %s\n", line); ++ } ++ } ++break2: ++ ++ return BCME_OK; ++} ++ ++static int ++dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size) ++{ ++ int bcmerror = 0; ++ uint msize = 512; ++ char *mbuffer = NULL; ++ char *console_buffer = NULL; ++ uint maxstrlen = 256; ++ char *str = NULL; ++ trap_t tr; ++ sdpcm_shared_t sdpcm_shared; ++ struct bcmstrbuf strbuf; ++ uint32 console_ptr, console_size, console_index; ++ uint8 line[CONSOLE_LINE_MAX], ch; ++ uint32 n, i, addr; ++ int rv; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (data == NULL) { ++ /* ++ * Called after a rx ctrl timeout. "data" is NULL. ++ * allocate memory to trace the trap or assert. ++ */ ++ size = msize; ++ mbuffer = data = MALLOC(bus->dhd->osh, msize); ++ if (mbuffer == NULL) { ++ AP6211_ERR("%s: MALLOC(%d) failed \n", __FUNCTION__, msize); ++ bcmerror = BCME_NOMEM; ++ goto done; ++ } ++ } ++ ++ if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) { ++ AP6211_ERR("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen); ++ bcmerror = BCME_NOMEM; ++ goto done; ++ } ++ ++ if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0) ++ goto done; ++ ++ bcm_binit(&strbuf, data, size); ++ ++ bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n", ++ sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr); ++ ++ if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) { ++ /* NOTE: Misspelled assert is intentional - DO NOT FIX. ++ * (Avoids conflict with real asserts for programmatic parsing of output.) ++ */ ++ bcm_bprintf(&strbuf, "Assrt not built in dongle\n"); ++ } ++ ++ if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) { ++ /* NOTE: Misspelled assert is intentional - DO NOT FIX. ++ * (Avoids conflict with real asserts for programmatic parsing of output.) ++ */ ++ bcm_bprintf(&strbuf, "No trap%s in dongle", ++ (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) ++ ?"/assrt" :""); ++ } else { ++ if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) { ++ /* Download assert */ ++ bcm_bprintf(&strbuf, "Dongle assert"); ++ if (sdpcm_shared.assert_exp_addr != 0) { ++ str[0] = '\0'; ++ if ((bcmerror = dhdsdio_membytes(bus, FALSE, ++ sdpcm_shared.assert_exp_addr, ++ (uint8 *)str, maxstrlen)) < 0) ++ goto done; ++ ++ str[maxstrlen - 1] = '\0'; ++ bcm_bprintf(&strbuf, " expr \"%s\"", str); ++ } ++ ++ if (sdpcm_shared.assert_file_addr != 0) { ++ str[0] = '\0'; ++ if ((bcmerror = dhdsdio_membytes(bus, FALSE, ++ sdpcm_shared.assert_file_addr, ++ (uint8 *)str, maxstrlen)) < 0) ++ goto done; ++ ++ str[maxstrlen - 1] = '\0'; ++ bcm_bprintf(&strbuf, " file \"%s\"", str); ++ } ++ ++ bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line); ++ } ++ ++ if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { ++ bus->dhd->dongle_trap_occured = TRUE; ++ if ((bcmerror = dhdsdio_membytes(bus, FALSE, ++ sdpcm_shared.trap_addr, ++ (uint8*)&tr, sizeof(trap_t))) < 0) ++ goto done; ++ ++ bcm_bprintf(&strbuf, ++ "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," ++ "lp 0x%x, rpc 0x%x Trap offset 0x%x, " ++ "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, " ++ "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n", ++ ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), ++ ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), ++ ltoh32(sdpcm_shared.trap_addr), ++ ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), ++ ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); ++ ++ addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log); ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, ++ (uint8 *)&console_ptr, sizeof(console_ptr))) < 0) ++ goto printbuf; ++ ++ addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size); ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, ++ (uint8 *)&console_size, sizeof(console_size))) < 0) ++ goto printbuf; ++ ++ addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx); ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, ++ (uint8 *)&console_index, sizeof(console_index))) < 0) ++ goto printbuf; ++ ++ console_ptr = ltoh32(console_ptr); ++ console_size = ltoh32(console_size); ++ console_index = ltoh32(console_index); ++ ++ if (console_size > CONSOLE_BUFFER_MAX || ++ !(console_buffer = MALLOC(bus->dhd->osh, console_size))) ++ goto printbuf; ++ ++ if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr, ++ (uint8 *)console_buffer, console_size)) < 0) ++ goto printbuf; ++ ++ for (i = 0, n = 0; i < console_size; i += n + 1) { ++ for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { ++ ch = console_buffer[(console_index + i + n) % console_size]; ++ if (ch == '\n') ++ break; ++ line[n] = ch; ++ } ++ ++ ++ if (n > 0) { ++ if (line[n - 1] == '\r') ++ n--; ++ line[n] = 0; ++ /* Don't use DHD_ERROR macro since we print ++ * a lot of information quickly. The macro ++ * will truncate a lot of the printfs ++ */ ++ ++ if (dhd_msg_level & DHD_ERROR_VAL) ++ AP6211_DEBUG("CONSOLE: %s\n", line); ++ } ++ } ++ } ++ } ++ ++printbuf: ++ if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) { ++ AP6211_DEBUG("%s: %s\n", __FUNCTION__, strbuf.origbuf); ++ } ++ ++ ++done: ++ if (mbuffer) ++ MFREE(bus->dhd->osh, mbuffer, msize); ++ if (str) ++ MFREE(bus->dhd->osh, str, maxstrlen); ++ if (console_buffer) ++ MFREE(bus->dhd->osh, console_buffer, console_size); ++ ++ return bcmerror; ++} ++#endif /* #ifdef DHD_DEBUG */ ++ ++ ++int ++dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len) ++{ ++ int bcmerror = BCME_OK; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ /* Basic sanity checks */ ++ if (bus->dhd->up) { ++ bcmerror = BCME_NOTDOWN; ++ goto err; ++ } ++ if (!len) { ++ bcmerror = BCME_BUFTOOSHORT; ++ goto err; ++ } ++ ++ /* Free the old ones and replace with passed variables */ ++ if (bus->vars) ++ MFREE(bus->dhd->osh, bus->vars, bus->varsz); ++ ++ bus->vars = MALLOC(bus->dhd->osh, len); ++ bus->varsz = bus->vars ? len : 0; ++ if (bus->vars == NULL) { ++ bcmerror = BCME_NOMEM; ++ goto err; ++ } ++ ++ /* Copy the passed variables, which should include the terminating double-null */ ++ bcopy(arg, bus->vars, bus->varsz); ++err: ++ return bcmerror; ++} ++ ++#ifdef DHD_DEBUG ++ ++#define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24) ++#define CC_CHIPCTRL_JTAG_SEL (1 << 3) ++#define CC_CHIPCTRL_GPIO_SEL (0x3) ++#define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334 (1 << 28) ++ ++static int ++dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror) ++{ ++ int int_val; ++ uint32 addr, data, uart_enab = 0; ++ uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL; ++ uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL; ++ ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); ++ data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); ++ *bcmerror = 0; ++ ++ bcmsdh_reg_write(bus->sdh, addr, 4, 1); ++ if (bcmsdh_regfail(bus->sdh)) { ++ *bcmerror = BCME_SDIO_ERROR; ++ return -1; ++ } ++ int_val = bcmsdh_reg_read(bus->sdh, data, 4); ++ if (bcmsdh_regfail(bus->sdh)) { ++ *bcmerror = BCME_SDIO_ERROR; ++ return -1; ++ } ++ if (bus->sih->chip == BCM4330_CHIP_ID) { ++ uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB; ++ } ++ else if (bus->sih->chip == BCM4334_CHIP_ID || ++ bus->sih->chip == BCM43341_CHIP_ID) { ++ if (enable) { ++ /* Moved to PMU chipcontrol 1 from 4330 */ ++ int_val &= ~gpio_sel; ++ int_val |= jtag_sel; ++ } else { ++ int_val |= gpio_sel; ++ int_val &= ~jtag_sel; ++ } ++ uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334; ++ } ++ ++ if (!set) ++ return (int_val & uart_enab); ++ if (enable) ++ int_val |= uart_enab; ++ else ++ int_val &= ~uart_enab; ++ bcmsdh_reg_write(bus->sdh, data, 4, int_val); ++ if (bcmsdh_regfail(bus->sdh)) { ++ *bcmerror = BCME_SDIO_ERROR; ++ return -1; ++ } ++ if (bus->sih->chip == BCM4330_CHIP_ID) { ++ uint32 chipcontrol; ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol); ++ chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4); ++ chipcontrol &= ~jtag_sel; ++ if (enable) { ++ chipcontrol |= jtag_sel; ++ chipcontrol &= ~gpio_sel; ++ } ++ bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol); ++ } ++ ++ return (int_val & uart_enab); ++} ++#endif ++ ++static int ++dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, ++ void *params, int plen, void *arg, int len, int val_size) ++{ ++ int bcmerror = 0; ++ int32 int_val = 0; ++ bool bool_val = 0; ++ ++ AP6211_DEBUG("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", ++ __FUNCTION__, actionid, name, params, plen, arg, len, val_size); ++ ++ if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) ++ goto exit; ++ ++ if (plen >= (int)sizeof(int_val)) ++ bcopy(params, &int_val, sizeof(int_val)); ++ ++ bool_val = (int_val != 0) ? TRUE : FALSE; ++ ++ ++ /* Some ioctls use the bus */ ++ dhd_os_sdlock(bus->dhd); ++ ++ /* Check if dongle is in reset. If so, only allow DEVRESET iovars */ ++ if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) || ++ actionid == IOV_GVAL(IOV_DEVRESET))) { ++ bcmerror = BCME_NOTREADY; ++ goto exit; ++ } ++ ++ /* ++ * Special handling for keepSdioOn: New SDIO Wake-up Mechanism ++ */ ++ if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) { ++ dhdsdio_clk_kso_iovar(bus, bool_val); ++ goto exit; ++ } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) { ++ { ++ dhdsdio_clk_devsleep_iovar(bus, bool_val); ++ if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) { ++ AP6211_DEBUG("INT pending in devsleep 1, dpc_sched: %d\n", ++ bus->dpc_sched); ++ if (!bus->dpc_sched) { ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ } ++ } ++ } ++ goto exit; ++ } ++ ++ /* Handle sleep stuff before any clock mucking */ ++ if (vi->varid == IOV_SLEEP) { ++ if (IOV_ISSET(actionid)) { ++ bcmerror = dhdsdio_bussleep(bus, bool_val); ++ } else { ++ int_val = (int32)bus->sleeping; ++ bcopy(&int_val, arg, val_size); ++ } ++ goto exit; ++ } ++ ++ /* Request clock to allow SDIO accesses */ ++ if (!bus->dhd->dongle_reset) { ++ BUS_WAKE(bus); ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ } ++ ++ switch (actionid) { ++ case IOV_GVAL(IOV_INTR): ++ int_val = (int32)bus->intr; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_INTR): ++ bus->intr = bool_val; ++ bus->intdis = FALSE; ++ if (bus->dhd->up) { ++ if (bus->intr) { ++ AP6211_DEBUG("%s: enable SDIO device interrupts\n", __FUNCTION__); ++ bcmsdh_intr_enable(bus->sdh); ++ } else { ++ AP6211_DEBUG("%s: disable SDIO interrupts\n", __FUNCTION__); ++ bcmsdh_intr_disable(bus->sdh); ++ } ++ } ++ break; ++ ++ case IOV_GVAL(IOV_POLLRATE): ++ int_val = (int32)bus->pollrate; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_POLLRATE): ++ bus->pollrate = (uint)int_val; ++ bus->poll = (bus->pollrate != 0); ++ break; ++ ++ case IOV_GVAL(IOV_IDLETIME): ++ int_val = bus->idletime; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_IDLETIME): ++ if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) { ++ bcmerror = BCME_BADARG; ++ } else { ++ bus->idletime = int_val; ++ } ++ break; ++ ++ case IOV_GVAL(IOV_IDLECLOCK): ++ int_val = (int32)bus->idleclock; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_IDLECLOCK): ++ bus->idleclock = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_SD1IDLE): ++ int_val = (int32)sd1idle; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SD1IDLE): ++ sd1idle = bool_val; ++ break; ++ ++ ++ case IOV_SVAL(IOV_MEMBYTES): ++ case IOV_GVAL(IOV_MEMBYTES): ++ { ++ uint32 address; ++ uint size, dsize; ++ uint8 *data; ++ ++ bool set = (actionid == IOV_SVAL(IOV_MEMBYTES)); ++ ++ ASSERT(plen >= 2*sizeof(int)); ++ ++ address = (uint32)int_val; ++ bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val)); ++ size = (uint)int_val; ++ ++ /* Do some validation */ ++ dsize = set ? plen - (2 * sizeof(int)) : len; ++ if (dsize < size) { ++ AP6211_ERR("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n", ++ __FUNCTION__, (set ? "set" : "get"), address, size, dsize); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ AP6211_DEBUG("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__, ++ (set ? "write" : "read"), size, address); ++ ++ /* If we know about SOCRAM, check for a fit */ ++ if ((bus->orig_ramsize) && ++ ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) ++ { ++ uint8 enable, protect, remap; ++ si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); ++ if (!enable || protect) { ++ AP6211_ERR("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n", ++ __FUNCTION__, bus->orig_ramsize, size, address); ++ AP6211_DEBUG("%s: socram enable %d, protect %d\n", ++ __FUNCTION__, enable, protect); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) { ++ uint32 devramsize = si_socdevram_size(bus->sih); ++ if ((address < SOCDEVRAM_ARM_ADDR) || ++ (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) { ++ AP6211_ERR("%s: bad address 0x%08x, size 0x%08x\n", ++ __FUNCTION__, address, size); ++ AP6211_DEBUG("%s: socram range 0x%08x,size 0x%08x\n", ++ __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ /* move it such that address is real now */ ++ address -= SOCDEVRAM_ARM_ADDR; ++ address += SOCDEVRAM_BP_ADDR; ++ AP6211_DEBUG("%s: Request to %s %d bytes @ Mapped address 0x%08x\n", ++ __FUNCTION__, (set ? "write" : "read"), size, address); ++ } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) { ++ /* Can not access remap region while devram remap bit is set ++ * ROM content would be returned in this case ++ */ ++ AP6211_ERR("%s: Need to disable remap for address 0x%08x\n", ++ __FUNCTION__, address); ++ bcmerror = BCME_ERROR; ++ break; ++ } ++ } ++ ++ /* Generate the actual data pointer */ ++ data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg; ++ ++ /* Call to do the transfer */ ++ bcmerror = dhdsdio_membytes(bus, set, address, data, size); ++ ++ break; ++ } ++ ++ case IOV_GVAL(IOV_MEMSIZE): ++ int_val = (int32)bus->ramsize; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_SDIOD_DRIVE): ++ int_val = (int32)dhd_sdiod_drive_strength; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SDIOD_DRIVE): ++ dhd_sdiod_drive_strength = int_val; ++ si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength); ++ break; ++ ++ case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): ++ bcmerror = dhdsdio_download_state(bus, bool_val); ++ break; ++ ++ case IOV_SVAL(IOV_SOCRAM_STATE): ++ bcmerror = dhdsdio_download_state(bus, bool_val); ++ break; ++ ++ case IOV_SVAL(IOV_VARS): ++ bcmerror = dhdsdio_downloadvars(bus, arg, len); ++ break; ++ ++ case IOV_GVAL(IOV_READAHEAD): ++ int_val = (int32)dhd_readahead; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_READAHEAD): ++ if (bool_val && !dhd_readahead) ++ bus->nextlen = 0; ++ dhd_readahead = bool_val; ++ break; ++ ++ case IOV_GVAL(IOV_SDRXCHAIN): ++ int_val = (int32)bus->use_rxchain; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SDRXCHAIN): ++ if (bool_val && !bus->sd_rxchain) ++ bcmerror = BCME_UNSUPPORTED; ++ else ++ bus->use_rxchain = bool_val; ++ break; ++ case IOV_GVAL(IOV_ALIGNCTL): ++ int_val = (int32)dhd_alignctl; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_ALIGNCTL): ++ dhd_alignctl = bool_val; ++ break; ++ ++ case IOV_GVAL(IOV_SDALIGN): ++ int_val = DHD_SDALIGN; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++#ifdef DHD_DEBUG ++ case IOV_GVAL(IOV_VARS): ++ if (bus->varsz < (uint)len) ++ bcopy(bus->vars, arg, bus->varsz); ++ else ++ bcmerror = BCME_BUFTOOSHORT; ++ break; ++#endif /* DHD_DEBUG */ ++ ++#ifdef DHD_DEBUG ++ case IOV_GVAL(IOV_SDREG): ++ { ++ sdreg_t *sd_ptr; ++ uint32 addr, size; ++ ++ sd_ptr = (sdreg_t *)params; ++ ++ addr = (uintptr)bus->regs + sd_ptr->offset; ++ size = sd_ptr->func; ++ int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); ++ if (bcmsdh_regfail(bus->sdh)) ++ bcmerror = BCME_SDIO_ERROR; ++ bcopy(&int_val, arg, sizeof(int32)); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_SDREG): ++ { ++ sdreg_t *sd_ptr; ++ uint32 addr, size; ++ ++ sd_ptr = (sdreg_t *)params; ++ ++ addr = (uintptr)bus->regs + sd_ptr->offset; ++ size = sd_ptr->func; ++ bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value); ++ if (bcmsdh_regfail(bus->sdh)) ++ bcmerror = BCME_SDIO_ERROR; ++ break; ++ } ++ ++ /* Same as above, but offset is not backplane (not SDIO core) */ ++ case IOV_GVAL(IOV_SBREG): ++ { ++ sdreg_t sdreg; ++ uint32 addr, size; ++ ++ bcopy(params, &sdreg, sizeof(sdreg)); ++ ++ addr = SI_ENUM_BASE + sdreg.offset; ++ size = sdreg.func; ++ int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); ++ if (bcmsdh_regfail(bus->sdh)) ++ bcmerror = BCME_SDIO_ERROR; ++ bcopy(&int_val, arg, sizeof(int32)); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_SBREG): ++ { ++ sdreg_t sdreg; ++ uint32 addr, size; ++ ++ bcopy(params, &sdreg, sizeof(sdreg)); ++ ++ addr = SI_ENUM_BASE + sdreg.offset; ++ size = sdreg.func; ++ bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value); ++ if (bcmsdh_regfail(bus->sdh)) ++ bcmerror = BCME_SDIO_ERROR; ++ break; ++ } ++ ++ case IOV_GVAL(IOV_SDCIS): ++ { ++ *(char *)arg = 0; ++ ++ bcmstrcat(arg, "\nFunc 0\n"); ++ bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); ++ bcmstrcat(arg, "\nFunc 1\n"); ++ bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); ++ bcmstrcat(arg, "\nFunc 2\n"); ++ bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); ++ break; ++ } ++ ++ case IOV_GVAL(IOV_FORCEEVEN): ++ int_val = (int32)forcealign; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_FORCEEVEN): ++ forcealign = bool_val; ++ break; ++ ++ case IOV_GVAL(IOV_TXBOUND): ++ int_val = (int32)dhd_txbound; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_TXBOUND): ++ dhd_txbound = (uint)int_val; ++ break; ++ ++ case IOV_GVAL(IOV_RXBOUND): ++ int_val = (int32)dhd_rxbound; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_RXBOUND): ++ dhd_rxbound = (uint)int_val; ++ break; ++ ++ case IOV_GVAL(IOV_TXMINMAX): ++ int_val = (int32)dhd_txminmax; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_TXMINMAX): ++ dhd_txminmax = (uint)int_val; ++ break; ++ ++ case IOV_GVAL(IOV_SERIALCONS): ++ int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror); ++ if (bcmerror != 0) ++ break; ++ ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SERIALCONS): ++ dhd_serialconsole(bus, TRUE, bool_val, &bcmerror); ++ break; ++ ++ ++ ++#endif /* DHD_DEBUG */ ++ ++ ++#ifdef SDTEST ++ case IOV_GVAL(IOV_EXTLOOP): ++ int_val = (int32)bus->ext_loop; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_EXTLOOP): ++ bus->ext_loop = bool_val; ++ break; ++ ++ case IOV_GVAL(IOV_PKTGEN): ++ bcmerror = dhdsdio_pktgen_get(bus, arg); ++ break; ++ ++ case IOV_SVAL(IOV_PKTGEN): ++ bcmerror = dhdsdio_pktgen_set(bus, arg); ++ break; ++#endif /* SDTEST */ ++ ++#if defined(SDIO_CRC_ERROR_FIX) ++ case IOV_GVAL(IOV_WATERMARK): ++ int_val = (int32)watermark; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_WATERMARK): ++ watermark = (uint)int_val; ++ watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark; ++ AP6211_DEBUG("Setting watermark as 0x%x.\n", watermark); ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL); ++ break; ++ ++ case IOV_GVAL(IOV_MESBUSYCTRL): ++ int_val = (int32)mesbusyctrl; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_MESBUSYCTRL): ++ mesbusyctrl = (uint)int_val; ++ mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK) ++ ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl; ++ AP6211_DEBUG("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl); ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, ++ ((uint8)mesbusyctrl | 0x80), NULL); ++ break; ++#endif /* SDIO_CRC_ERROR_FIX */ ++ ++ case IOV_GVAL(IOV_DONGLEISOLATION): ++ int_val = bus->dhd->dongle_isolation; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DONGLEISOLATION): ++ bus->dhd->dongle_isolation = bool_val; ++ break; ++ ++ case IOV_SVAL(IOV_DEVRESET): ++ AP6211_DEBUG("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n", ++ __FUNCTION__, bool_val, bus->dhd->dongle_reset, ++ bus->dhd->busstate); ++ ++ ASSERT(bus->dhd->osh); ++ /* ASSERT(bus->cl_devid); */ ++ ++ dhd_bus_devreset(bus->dhd, (uint8)bool_val); ++ ++ break; ++#ifdef SOFTAP ++ case IOV_GVAL(IOV_FWPATH): ++ { ++ uint32 fw_path_len; ++ ++ fw_path_len = strlen(bus->fw_path); ++ AP6211_DEBUG("[softap] get fwpath, l=%d\n", len); ++ ++ if (fw_path_len > len-1) { ++ bcmerror = BCME_BUFTOOSHORT; ++ break; ++ } ++ ++ if (fw_path_len) { ++ bcopy(bus->fw_path, arg, fw_path_len); ++ ((uchar*)arg)[fw_path_len] = 0; ++ } ++ break; ++ } ++ ++ case IOV_SVAL(IOV_FWPATH): ++ AP6211_DEBUG("[softap] set fwpath, idx=%d\n", int_val); ++ ++ switch (int_val) { ++ case 1: ++ bus->fw_path = fw_path; /* ordinary one */ ++ break; ++ case 2: ++ bus->fw_path = fw_path2; ++ break; ++ default: ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ AP6211_DEBUG("[softap] new fw path: %s\n", (bus->fw_path[0] ? bus->fw_path : "NULL")); ++ break; ++ ++#endif /* SOFTAP */ ++ case IOV_GVAL(IOV_DEVRESET): ++ AP6211_DEBUG("%s: Called get IOV_DEVRESET\n", __FUNCTION__); ++ ++ /* Get its status */ ++ int_val = (bool) bus->dhd->dongle_reset; ++ bcopy(&int_val, arg, val_size); ++ ++ break; ++ ++ case IOV_GVAL(IOV_KSO): ++ int_val = dhdsdio_sleepcsr_get(bus); ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_DEVCAP): ++ int_val = dhdsdio_devcap_get(bus); ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DEVCAP): ++ dhdsdio_devcap_set(bus, (uint8) int_val); ++ break; ++ ++#ifdef BCMSDIOH_TXGLOM ++ case IOV_GVAL(IOV_TXGLOMSIZE): ++ int_val = (int32)bus->glomsize; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_TXGLOMSIZE): ++ if (int_val > SDPCM_MAXGLOM_SIZE) { ++ bcmerror = BCME_ERROR; ++ } else { ++ bus->glomsize = (uint)int_val; ++ } ++ break; ++ case IOV_GVAL(IOV_TXGLOMMODE): ++ int_val = (int32)bus->glom_mode; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_TXGLOMMODE): ++ if ((int_val != SDPCM_TXGLOM_CPY) && (int_val != SDPCM_TXGLOM_MDESC)) { ++ bcmerror = BCME_RANGE; ++ } else { ++ if ((bus->glom_mode = bcmsdh_set_mode(bus->sdh, (uint)int_val)) != int_val) ++ bcmerror = BCME_ERROR; ++ } ++ break; ++#endif /* BCMSDIOH_TXGLOM */ ++ default: ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++ ++exit: ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { ++ bus->activity = FALSE; ++ dhdsdio_clkctl(bus, CLK_NONE, TRUE); ++ } ++ ++ dhd_os_sdunlock(bus->dhd); ++ ++ return bcmerror; ++} ++ ++static int ++dhdsdio_write_vars(dhd_bus_t *bus) ++{ ++ int bcmerror = 0; ++ uint32 varsize, phys_size; ++ uint32 varaddr; ++ uint8 *vbuffer; ++ uint32 varsizew; ++#ifdef DHD_DEBUG ++ uint8 *nvram_ularray; ++#endif /* DHD_DEBUG */ ++ ++ /* Even if there are no vars are to be written, we still need to set the ramsize. */ ++ varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0; ++ varaddr = (bus->ramsize - 4) - varsize; ++ ++ varaddr += bus->dongle_ram_base; ++ ++ if (bus->vars) { ++ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) { ++ if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) { ++ AP6211_DEBUG("PR85623WAR in place\n"); ++ varsize += 4; ++ varaddr -= 4; ++ } ++ } ++ ++ vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize); ++ if (!vbuffer) ++ return BCME_NOMEM; ++ ++ bzero(vbuffer, varsize); ++ bcopy(bus->vars, vbuffer, bus->varsz); ++ ++ /* Write the vars list */ ++ bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize); ++#ifdef DHD_DEBUG ++ /* Verify NVRAM bytes */ ++ AP6211_DEBUG("Compare NVRAM dl & ul; varsize=%d\n", varsize); ++ nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize); ++ if (!nvram_ularray) ++ return BCME_NOMEM; ++ ++ /* Upload image to verify downloaded contents. */ ++ memset(nvram_ularray, 0xaa, varsize); ++ ++ /* Read the vars list to temp buffer for comparison */ ++ bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize); ++ if (bcmerror) { ++ AP6211_ERR("%s: error %d on reading %d nvram bytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, varsize, varaddr); ++ } ++ /* Compare the org NVRAM with the one read from RAM */ ++ if (memcmp(vbuffer, nvram_ularray, varsize)) { ++ AP6211_ERR("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__); ++ } else ++ AP6211_DEBUG("%s: Download, Upload and compare of NVRAM succeeded.\n", ++ __FUNCTION__); ++ ++ MFREE(bus->dhd->osh, nvram_ularray, varsize); ++#endif /* DHD_DEBUG */ ++ ++ MFREE(bus->dhd->osh, vbuffer, varsize); ++ } ++ ++ phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize; ++ ++ phys_size += bus->dongle_ram_base; ++ ++ /* adjust to the user specified RAM */ ++ AP6211_DEBUG("Physical memory size: %d, usable memory size: %d\n", ++ phys_size, bus->ramsize); ++ AP6211_DEBUG("Vars are at %d, orig varsize is %d\n", ++ varaddr, varsize); ++ varsize = ((phys_size - 4) - varaddr); ++ ++ /* ++ * Determine the length token: ++ * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits. ++ */ ++ if (bcmerror) { ++ varsizew = 0; ++ } else { ++ varsizew = varsize / 4; ++ varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); ++ varsizew = htol32(varsizew); ++ } ++ ++ AP6211_DEBUG("New varsize is %d, length token=0x%08x\n", varsize, varsizew); ++ ++ /* Write the length token to the last word */ ++ bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4), ++ (uint8*)&varsizew, 4); ++ ++ return bcmerror; ++} ++ ++static int ++dhdsdio_download_state(dhd_bus_t *bus, bool enter) ++{ ++ uint retries; ++ int bcmerror = 0; ++ int foundcr4 = 0; ++ ++ /* To enter download state, disable ARM and reset SOCRAM. ++ * To exit download state, simply reset ARM (default is RAM boot). ++ */ ++ if (enter) { ++ bus->alp_only = TRUE; ++ ++ if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && ++ !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { ++ if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { ++ foundcr4 = 1; ++ } else { ++ AP6211_ERR("%s: Failed to find ARM core!\n", __FUNCTION__); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ } ++ ++ if (!foundcr4) { ++ si_core_disable(bus->sih, 0); ++ if (bcmsdh_regfail(bus->sdh)) { ++ bcmerror = BCME_SDIO_ERROR; ++ goto fail; ++ } ++ ++ if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { ++ AP6211_ERR("%s: Failed to find SOCRAM core!\n", __FUNCTION__); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ ++ si_core_reset(bus->sih, 0, 0); ++ if (bcmsdh_regfail(bus->sdh)) { ++ AP6211_ERR("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__); ++ bcmerror = BCME_SDIO_ERROR; ++ goto fail; ++ } ++ ++ /* Disable remap for download */ ++ if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih)) ++ dhdsdio_devram_remap(bus, FALSE); ++ ++ /* Clear the top bit of memory */ ++ if (bus->ramsize) { ++ uint32 zeros = 0; ++ if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4) < 0) { ++ bcmerror = BCME_SDIO_ERROR; ++ goto fail; ++ } ++ } ++ } else { ++ /* For CR4, ++ * Halt ARM ++ * Remove ARM reset ++ * Read RAM base address [0x18_0000] ++ * [next] Download firmware ++ * [done at else] Populate the reset vector ++ * [done at else] Remove ARM halt ++ */ ++ /* Halt ARM & remove reset */ ++ si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT); ++ } ++ } else { ++ if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { ++ if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { ++ AP6211_ERR("%s: Failed to find SOCRAM core!\n", __FUNCTION__); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ ++ if (!si_iscoreup(bus->sih)) { ++ AP6211_ERR("%s: SOCRAM core is down after reset?\n", __FUNCTION__); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ ++ if ((bcmerror = dhdsdio_write_vars(bus))) { ++ AP6211_ERR("%s: could not write vars to RAM\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ /* Enable remap before ARM reset but after vars. ++ * No backplane access in remap mode ++ */ ++ if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih)) ++ dhdsdio_devram_remap(bus, TRUE); ++ ++ if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && ++ !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { ++ AP6211_ERR("%s: Can't change back to SDIO core?\n", __FUNCTION__); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); ++ ++ ++ if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && ++ !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { ++ AP6211_ERR("%s: Failed to find ARM core!\n", __FUNCTION__); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ } else { ++ /* cr4 has no socram, but tcm's */ ++ /* write vars */ ++ if ((bcmerror = dhdsdio_write_vars(bus))) { ++ AP6211_ERR("%s: could not write vars to RAM\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && ++ !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { ++ AP6211_ERR("%s: Can't change back to SDIO core?\n", __FUNCTION__); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); ++ ++ /* switch back to arm core again */ ++ if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { ++ AP6211_ERR("%s: Failed to find ARM CR4 core!\n", __FUNCTION__); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ /* write address 0 with reset instruction */ ++ bcmerror = dhdsdio_membytes(bus, TRUE, 0, ++ (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr)); ++ ++ /* now remove reset and halt and continue to run CR4 */ ++ } ++ ++ si_core_reset(bus->sih, 0, 0); ++ if (bcmsdh_regfail(bus->sdh)) { ++ AP6211_ERR("%s: Failure trying to reset ARM core?\n", __FUNCTION__); ++ bcmerror = BCME_SDIO_ERROR; ++ goto fail; ++ } ++ ++ /* Allow HT Clock now that the ARM is running. */ ++ bus->alp_only = FALSE; ++ ++ bus->dhd->busstate = DHD_BUS_LOAD; ++ } ++ ++fail: ++ /* Always return to SDIOD core */ ++ if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) ++ si_setcore(bus->sih, SDIOD_CORE_ID, 0); ++ ++ return bcmerror; ++} ++ ++int ++dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ const bcm_iovar_t *vi = NULL; ++ int bcmerror = 0; ++ int val_size; ++ uint32 actionid; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ ASSERT(name); ++ ASSERT(len >= 0); ++ ++ /* Get MUST have return space */ ++ ASSERT(set || (arg && len)); ++ ++ /* Set does NOT take qualifiers */ ++ ASSERT(!set || (!params && !plen)); ++ ++ /* Look up var locally; if not found pass to host driver */ ++ if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) { ++ dhd_os_sdlock(bus->dhd); ++ ++ BUS_WAKE(bus); ++ ++ /* Turn on clock in case SD command needs backplane */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set); ++ ++ /* Check for bus configuration changes of interest */ ++ ++ /* If it was divisor change, read the new one */ ++ if (set && strcmp(name, "sd_divisor") == 0) { ++ if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, ++ &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { ++ bus->sd_divisor = -1; ++ AP6211_ERR("%s: fail on %s get\n", __FUNCTION__, name); ++ } else { ++ AP6211_DEBUG("%s: noted %s update, value now %d\n", ++ __FUNCTION__, name, bus->sd_divisor); ++ } ++ } ++ /* If it was a mode change, read the new one */ ++ if (set && strcmp(name, "sd_mode") == 0) { ++ if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, ++ &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { ++ bus->sd_mode = -1; ++ AP6211_ERR("%s: fail on %s get\n", __FUNCTION__, name); ++ } else { ++ AP6211_DEBUG("%s: noted %s update, value now %d\n", ++ __FUNCTION__, name, bus->sd_mode); ++ } ++ } ++ /* Similar check for blocksize change */ ++ if (set && strcmp(name, "sd_blocksize") == 0) { ++ int32 fnum = 2; ++ if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32), ++ &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { ++ bus->blocksize = 0; ++ AP6211_ERR("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"); ++ } else { ++ AP6211_DEBUG("%s: noted %s update, value now %d\n", ++ __FUNCTION__, "sd_blocksize", bus->blocksize); ++ } ++ } ++ bus->roundup = MIN(max_roundup, bus->blocksize); ++ ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { ++ bus->activity = FALSE; ++ dhdsdio_clkctl(bus, CLK_NONE, TRUE); ++ } ++ ++ dhd_os_sdunlock(bus->dhd); ++ goto exit; ++ } ++ ++ AP6211_DEBUG("%s: %s %s, len %d plen %d\n", __FUNCTION__, ++ name, (set ? "set" : "get"), len, plen); ++ ++ /* set up 'params' pointer in case this is a set command so that ++ * the convenience int and bool code can be common to set and get ++ */ ++ if (params == NULL) { ++ params = arg; ++ plen = len; ++ } ++ ++ if (vi->type == IOVT_VOID) ++ val_size = 0; ++ else if (vi->type == IOVT_BUFFER) ++ val_size = len; ++ else ++ /* all other types are integer sized */ ++ val_size = sizeof(int); ++ ++ actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); ++ bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size); ++ ++exit: ++ return bcmerror; ++} ++ ++void ++dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) ++{ ++ osl_t *osh; ++ uint32 local_hostintmask; ++ uint8 saveclk, dat; ++ uint retries; ++ int err; ++ if (!bus->dhd) ++ return; ++ ++ osh = bus->dhd->osh; ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ bcmsdh_waitlockfree(NULL); ++ ++ if (enforce_mutex) ++ dhd_os_sdlock(bus->dhd); ++ ++ if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) { ++ /* if Firmware already hangs disbale any interrupt */ ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ bus->hostintmask = 0; ++ bcmsdh_intr_disable(bus->sdh); ++ } else { ++ BUS_WAKE(bus); ++ ++ if (KSO_ENAB(bus)) { ++ /* Mask the interrupt */ ++ dat = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTEN, NULL); ++ dat &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTEN, dat, NULL); ++ } ++ ++ /* Change our idea of bus state */ ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ ++ if (KSO_ENAB(bus)) { ++ ++ /* Enable clock for device interrupts */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ /* Disable and clear interrupts at the chip level also */ ++ W_SDREG(0, &bus->regs->hostintmask, retries); ++ local_hostintmask = bus->hostintmask; ++ bus->hostintmask = 0; ++ ++ /* Force clocks on backplane to be sure F2 interrupt propagates */ ++ saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if (!err) { ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ (saveclk | SBSDIO_FORCE_HT), &err); ++ } ++ if (err) { ++ AP6211_ERR("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err); ++ } ++ ++ /* Turn off the bus (F2), free any pending packets */ ++ AP6211_DEBUG("%s: disable SDIO interrupts\n", __FUNCTION__); ++ bcmsdh_intr_disable(bus->sdh); ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); ++ ++ /* Clear any pending interrupts now that F2 is disabled */ ++ W_SDREG(local_hostintmask, &bus->regs->intstatus, retries); ++ } ++ ++ /* Turn off the backplane clock (only) */ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ } ++ ++ /* Clear the data packet queues */ ++ pktq_flush(osh, &bus->txq, TRUE, NULL, 0); ++ ++ /* Clear any held glomming stuff */ ++ if (bus->glomd) ++ PKTFREE(osh, bus->glomd, FALSE); ++ ++ if (bus->glom) ++ PKTFREE(osh, bus->glom, FALSE); ++ ++ bus->glom = bus->glomd = NULL; ++ ++ /* Clear rx control and wake any waiters */ ++ bus->rxlen = 0; ++ dhd_os_ioctl_resp_wake(bus->dhd); ++ ++ /* Reset some F2 state stuff */ ++ bus->rxskip = FALSE; ++ bus->tx_seq = bus->rx_seq = 0; ++ ++ if (enforce_mutex) ++ dhd_os_sdunlock(bus->dhd); ++} ++ ++#ifdef BCMSDIOH_TXGLOM ++void ++dhd_txglom_enable(dhd_pub_t *dhdp, bool enable) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ ++ char buf[256]; ++ uint32 rxglom; ++ int32 ret; ++ ++ if (enable) { ++ rxglom = 1; ++ memset(buf, 0, sizeof(buf)); ++ bcm_mkiovar("bus:rxglom", ++ (void *)&rxglom, ++ 4, buf, sizeof(buf)); ++ ret = dhd_wl_ioctl_cmd(dhdp, ++ WLC_SET_VAR, buf, ++ sizeof(buf), TRUE, 0); ++ if (!(ret < 0)) { ++ bus->glom_enable = TRUE; ++ } ++ } else { ++ bus->glom_enable = FALSE; ++ } ++} ++#endif /* BCMSDIOH_TXGLOM */ ++ ++int ++dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ dhd_timeout_t tmo; ++ uint retries = 0; ++ uint8 ready, enable; ++ int err, ret = 0; ++ uint8 saveclk; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ ASSERT(bus->dhd); ++ if (!bus->dhd) ++ return 0; ++ ++ if (enforce_mutex) ++ dhd_os_sdlock(bus->dhd); ++ ++ /* Make sure backplane clock is on, needed to generate F2 interrupt */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ if (bus->clkstate != CLK_AVAIL) { ++ AP6211_ERR("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate); ++ ret = -1; ++ goto exit; ++ } ++ ++ ++ /* Force clocks on backplane to be sure F2 interrupt propagates */ ++ saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if (!err) { ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ (saveclk | SBSDIO_FORCE_HT), &err); ++ } ++ if (err) { ++ AP6211_ERR("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err); ++ ret = -1; ++ goto exit; ++ } ++ ++ /* Enable function 2 (frame transfers) */ ++ W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT), ++ &bus->regs->tosbmailboxdata, retries); ++ enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); ++ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); ++ ++ /* Give the dongle some time to do its thing and set IOR2 */ ++ dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000); ++ ++ ready = 0; ++ while (ready != enable && !dhd_timeout_expired(&tmo)) ++ ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL); ++ ++ AP6211_DEBUG("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n", ++ __FUNCTION__, enable, ready, tmo.elapsed); ++ ++ ++ /* If F2 successfully enabled, set core and enable interrupts */ ++ if (ready == enable) { ++ /* Make sure we're talking to the core. */ ++ if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0))) ++ bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0); ++ ASSERT(bus->regs != NULL); ++ ++ /* Set up the interrupt mask and enable interrupts */ ++ bus->hostintmask = HOSTINTMASK; ++ /* corerev 4 could use the newer interrupt logic to detect the frames */ ++ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) && ++ (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) { ++ bus->hostintmask &= ~I_HMB_FRAME_IND; ++ bus->hostintmask |= I_XMTDATA_AVAIL; ++ } ++ W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); ++#ifdef SDIO_CRC_ERROR_FIX ++ if (bus->blocksize < 512) { ++ mesbusyctrl = watermark = bus->blocksize / 4; ++ } ++#endif /* SDIO_CRC_ERROR_FIX */ ++ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err); ++#ifdef SDIO_CRC_ERROR_FIX ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, ++ (uint8)mesbusyctrl|0x80, &err); ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, ++ SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK, NULL); ++#endif /* SDIO_CRC_ERROR_FIX */ ++ ++ /* Set bus state according to enable result */ ++ dhdp->busstate = DHD_BUS_DATA; ++ ++ /* bcmsdh_intr_unmask(bus->sdh); */ ++ ++ bus->intdis = FALSE; ++ if (bus->intr) { ++ AP6211_DEBUG("%s: enable SDIO device interrupts\n", __FUNCTION__); ++ bcmsdh_intr_enable(bus->sdh); ++ } else { ++ AP6211_DEBUG("%s: disable SDIO interrupts\n", __FUNCTION__); ++ bcmsdh_intr_disable(bus->sdh); ++ } ++ ++ } ++ ++ ++ else { ++ /* Disable F2 again */ ++ enable = SDIO_FUNC_ENABLE_1; ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); ++ } ++ ++ if (dhdsdio_sr_cap(bus)) ++ dhdsdio_sr_init(bus); ++ else ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); ++ ++ /* If we didn't come up, turn off backplane clock */ ++ if (dhdp->busstate != DHD_BUS_DATA) ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ ++exit: ++ if (enforce_mutex) ++ dhd_os_sdunlock(bus->dhd); ++ ++ return ret; ++} ++ ++static void ++dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx) ++{ ++ bcmsdh_info_t *sdh = bus->sdh; ++ sdpcmd_regs_t *regs = bus->regs; ++ uint retries = 0; ++ uint16 lastrbc; ++ uint8 hi, lo; ++ int err; ++ ++ AP6211_ERR("%s: %sterminate frame%s\n", __FUNCTION__, ++ (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")); ++ ++ if (!KSO_ENAB(bus)) { ++ AP6211_ERR("%s: Device asleep\n", __FUNCTION__); ++ return; ++ } ++ ++ if (abort) { ++ bcmsdh_abort(sdh, SDIO_FUNC_2); ++ } ++ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err); ++ bus->f1regdata++; ++ ++ /* Wait until the packet has been flushed (device/FIFO stable) */ ++ for (lastrbc = retries = 0xffff; retries > 0; retries--) { ++ hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL); ++ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, NULL); ++ bus->f1regdata += 2; ++ ++ if ((hi == 0) && (lo == 0)) ++ break; ++ ++ if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) { ++ AP6211_DEBUG("%s: count growing: last 0x%04x now 0x%04x\n", ++ __FUNCTION__, lastrbc, ((hi << 8) + lo)); ++ } ++ lastrbc = (hi << 8) + lo; ++ } ++ ++ if (!retries) { ++ AP6211_ERR("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc); ++ } else { ++ AP6211_DEBUG("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)); ++ } ++ ++ if (rtx) { ++ bus->rxrtx++; ++ W_SDREG(SMB_NAK, ®s->tosbmailbox, retries); ++ bus->f1regdata++; ++ if (retries <= retry_limit) { ++ bus->rxskip = TRUE; ++ } ++ } ++ ++ /* Clear partial in any case */ ++ bus->nextlen = 0; ++ ++ /* If we can't reach the device, signal failure */ ++ if (err || bcmsdh_regfail(sdh)) ++ bus->dhd->busstate = DHD_BUS_DOWN; ++} ++ ++static void ++dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff) ++{ ++ bcmsdh_info_t *sdh = bus->sdh; ++ uint rdlen, pad; ++ ++ int sdret; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ /* Control data already received in aligned rxctl */ ++ if ((bus->bus == SPI_BUS) && (!bus->usebufpool)) ++ goto gotpkt; ++ ++ ASSERT(bus->rxbuf); ++ /* Set rxctl for frame (w/optional alignment) */ ++ bus->rxctl = bus->rxbuf; ++ if (dhd_alignctl) { ++ bus->rxctl += firstread; ++ if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) ++ bus->rxctl += (DHD_SDALIGN - pad); ++ bus->rxctl -= firstread; ++ } ++ ASSERT(bus->rxctl >= bus->rxbuf); ++ ++ /* Copy the already-read portion over */ ++ bcopy(hdr, bus->rxctl, firstread); ++ if (len <= firstread) ++ goto gotpkt; ++ ++ /* Copy the full data pkt in gSPI case and process ioctl. */ ++ if (bus->bus == SPI_BUS) { ++ bcopy(hdr, bus->rxctl, len); ++ goto gotpkt; ++ } ++ ++ /* Raise rdlen to next SDIO block to avoid tail command */ ++ rdlen = len - firstread; ++ if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { ++ pad = bus->blocksize - (rdlen % bus->blocksize); ++ if ((pad <= bus->roundup) && (pad < bus->blocksize) && ++ ((len + pad) < bus->dhd->maxctl)) ++ rdlen += pad; ++ } else if (rdlen % DHD_SDALIGN) { ++ rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); ++ } ++ ++ /* Satisfy length-alignment requirements */ ++ if (forcealign && (rdlen & (ALIGNMENT - 1))) ++ rdlen = ROUNDUP(rdlen, ALIGNMENT); ++ ++ /* Drop if the read is too big or it exceeds our maximum */ ++ if ((rdlen + firstread) > bus->dhd->maxctl) { ++ AP6211_ERR("%s: %d-byte control read exceeds %d-byte buffer\n", ++ __FUNCTION__, rdlen, bus->dhd->maxctl); ++ bus->dhd->rx_errors++; ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ goto done; ++ } ++ ++ if ((len - doff) > bus->dhd->maxctl) { ++ AP6211_ERR("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", ++ __FUNCTION__, len, (len - doff), bus->dhd->maxctl); ++ bus->dhd->rx_errors++; bus->rx_toolong++; ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ goto done; ++ } ++ ++ ++ /* Read remainder of frame body into the rxctl buffer */ ++ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ (bus->rxctl + firstread), rdlen, NULL, NULL, NULL); ++ bus->f2rxdata++; ++ ASSERT(sdret != BCME_PENDING); ++ ++ /* Control frame failures need retransmission */ ++ if (sdret < 0) { ++ AP6211_ERR("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret); ++ bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */ ++ dhdsdio_rxfail(bus, TRUE, TRUE); ++ goto done; ++ } ++ ++gotpkt: ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_CTL_ON()) { ++ prhex("RxCtrl", bus->rxctl, len); ++ } ++#endif ++ ++ /* Point to valid data and indicate its length */ ++ bus->rxctl += doff; ++ bus->rxlen = len - doff; ++ ++done: ++ /* Awake any waiters */ ++ dhd_os_ioctl_resp_wake(bus->dhd); ++} ++ ++static uint8 ++dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) ++{ ++ uint16 dlen, totlen; ++ uint8 *dptr, num = 0; ++ ++ uint16 sublen, check; ++ void *pfirst, *plast, *pnext; ++ void * list_tail[DHD_MAX_IFS] = { NULL }; ++ void * list_head[DHD_MAX_IFS] = { NULL }; ++ uint8 idx; ++ osl_t *osh = bus->dhd->osh; ++ ++ int errcode; ++ uint8 chan, seq, doff, sfdoff; ++ uint8 txmax; ++ uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; ++ uint reorder_info_len; ++ ++ int ifidx = 0; ++ bool usechain = bus->use_rxchain; ++ ++ /* If packets, issue read(s) and send up packet chain */ ++ /* Return sequence numbers consumed? */ ++ ++ AP6211_DEBUG("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom); ++ ++ /* If there's a descriptor, generate the packet chain */ ++ if (bus->glomd) { ++ dhd_os_sdlock_rxq(bus->dhd); ++ ++ pfirst = plast = pnext = NULL; ++ dlen = (uint16)PKTLEN(osh, bus->glomd); ++ dptr = PKTDATA(osh, bus->glomd); ++ if (!dlen || (dlen & 1)) { ++ AP6211_ERR("%s: bad glomd len (%d), ignore descriptor\n", ++ __FUNCTION__, dlen); ++ dlen = 0; ++ } ++ ++ for (totlen = num = 0; dlen; num++) { ++ /* Get (and move past) next length */ ++ sublen = ltoh16_ua(dptr); ++ dlen -= sizeof(uint16); ++ dptr += sizeof(uint16); ++ if ((sublen < SDPCM_HDRLEN_RX) || ++ ((num == 0) && (sublen < (2 * SDPCM_HDRLEN_RX)))) { ++ AP6211_ERR("%s: descriptor len %d bad: %d\n", ++ __FUNCTION__, num, sublen); ++ pnext = NULL; ++ break; ++ } ++ if (sublen % DHD_SDALIGN) { ++ AP6211_ERR("%s: sublen %d not a multiple of %d\n", ++ __FUNCTION__, sublen, DHD_SDALIGN); ++ usechain = FALSE; ++ } ++ totlen += sublen; ++ ++ /* For last frame, adjust read len so total is a block multiple */ ++ if (!dlen) { ++ sublen += (ROUNDUP(totlen, bus->blocksize) - totlen); ++ totlen = ROUNDUP(totlen, bus->blocksize); ++ } ++ ++ /* Allocate/chain packet for next subframe */ ++ if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) { ++ AP6211_ERR("%s: PKTGET failed, num %d len %d\n", ++ __FUNCTION__, num, sublen); ++ break; ++ } ++ ASSERT(!PKTLINK(pnext)); ++ if (!pfirst) { ++ ASSERT(!plast); ++ pfirst = plast = pnext; ++ } else { ++ ASSERT(plast); ++ PKTSETNEXT(osh, plast, pnext); ++ plast = pnext; ++ } ++ ++ /* Adhere to start alignment requirements */ ++ PKTALIGN(osh, pnext, sublen, DHD_SDALIGN); ++ } ++ ++ /* If all allocations succeeded, save packet chain in bus structure */ ++ if (pnext) { ++ AP6211_DEBUG("%s: allocated %d-byte packet chain for %d subframes\n", ++ __FUNCTION__, totlen, num); ++ if (DHD_GLOM_ON() && bus->nextlen) { ++ if (totlen != bus->nextlen) { ++ AP6211_DEBUG("%s: glomdesc mismatch: nextlen %d glomdesc %d " ++ "rxseq %d\n", __FUNCTION__, bus->nextlen, ++ totlen, rxseq); ++ } ++ } ++ bus->glom = pfirst; ++ pfirst = pnext = NULL; ++ } else { ++ if (pfirst) ++ PKTFREE(osh, pfirst, FALSE); ++ bus->glom = NULL; ++ num = 0; ++ } ++ ++ /* Done with descriptor packet */ ++ PKTFREE(osh, bus->glomd, FALSE); ++ bus->glomd = NULL; ++ bus->nextlen = 0; ++ ++ dhd_os_sdunlock_rxq(bus->dhd); ++ } ++ ++ /* Ok -- either we just generated a packet chain, or had one from before */ ++ if (bus->glom) { ++ if (DHD_GLOM_ON()) { ++ AP6211_DEBUG("%s: attempt superframe read, packet chain:\n", __FUNCTION__); ++ for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) { ++ AP6211_DEBUG(" %p: %p len 0x%04x (%d)\n", ++ pnext, (uint8*)PKTDATA(osh, pnext), ++ PKTLEN(osh, pnext), PKTLEN(osh, pnext)); ++ } ++ } ++ ++ pfirst = bus->glom; ++ dlen = (uint16)pkttotlen(osh, pfirst); ++ ++ /* Do an SDIO read for the superframe. Configurable iovar to ++ * read directly into the chained packet, or allocate a large ++ * packet and and copy into the chain. ++ */ ++ if (usechain) { ++ errcode = dhd_bcmsdh_recv_buf(bus, ++ bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, ++ F2SYNC, (uint8*)PKTDATA(osh, pfirst), ++ dlen, pfirst, NULL, NULL); ++ } else if (bus->dataptr) { ++ errcode = dhd_bcmsdh_recv_buf(bus, ++ bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, ++ F2SYNC, bus->dataptr, ++ dlen, NULL, NULL, NULL); ++ sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr); ++ if (sublen != dlen) { ++ AP6211_ERR("%s: FAILED TO COPY, dlen %d sublen %d\n", ++ __FUNCTION__, dlen, sublen); ++ errcode = -1; ++ } ++ pnext = NULL; ++ } else { ++ AP6211_ERR("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen); ++ errcode = -1; ++ } ++ bus->f2rxdata++; ++ ASSERT(errcode != BCME_PENDING); ++ ++ /* On failure, kill the superframe, allow a couple retries */ ++ if (errcode < 0) { ++ AP6211_ERR("%s: glom read of %d bytes failed: %d\n", ++ __FUNCTION__, dlen, errcode); ++ bus->dhd->rx_errors++; ++ ++ if (bus->glomerr++ < 3) { ++ dhdsdio_rxfail(bus, TRUE, TRUE); ++ } else { ++ bus->glomerr = 0; ++ dhdsdio_rxfail(bus, TRUE, FALSE); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(osh, bus->glom, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ bus->rxglomfail++; ++ bus->glom = NULL; ++ } ++ return 0; ++ } ++ ++#ifdef DHD_DEBUG ++ if (DHD_GLOM_ON()) { ++ prhex("SUPERFRAME", PKTDATA(osh, pfirst), ++ MIN(PKTLEN(osh, pfirst), 48)); ++ } ++#endif ++ ++ ++ /* Validate the superframe header */ ++ dptr = (uint8 *)PKTDATA(osh, pfirst); ++ sublen = ltoh16_ua(dptr); ++ check = ltoh16_ua(dptr + sizeof(uint16)); ++ ++ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); ++ seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); ++ bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; ++ if ((bus->nextlen << 4) > MAX_RX_DATASZ) { ++ AP6211_DEBUG("%s: got frame w/nextlen too large (%d) seq %d\n", ++ __FUNCTION__, bus->nextlen, seq); ++ bus->nextlen = 0; ++ } ++ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); ++ txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); ++ ++ errcode = 0; ++ if ((uint16)~(sublen^check)) { ++ AP6211_ERR("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n", ++ __FUNCTION__, sublen, check); ++ errcode = -1; ++ } else if (ROUNDUP(sublen, bus->blocksize) != dlen) { ++ AP6211_ERR("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n", ++ __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen); ++ errcode = -1; ++ } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) { ++ AP6211_ERR("%s (superframe): bad channel %d\n", __FUNCTION__, ++ SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])); ++ errcode = -1; ++ } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { ++ AP6211_ERR("%s (superframe): got second descriptor?\n", __FUNCTION__); ++ errcode = -1; ++ } else if ((doff < SDPCM_HDRLEN_RX) || ++ (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN_RX))) { ++ AP6211_ERR("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n", ++ __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), ++ SDPCM_HDRLEN_RX); ++ errcode = -1; ++ } ++ ++ /* Check sequence number of superframe SW header */ ++ if (rxseq != seq) { ++ AP6211_DEBUG("%s: (superframe) rx_seq %d, expected %d\n", ++ __FUNCTION__, seq, rxseq); ++ bus->rx_badseq++; ++ rxseq = seq; ++ } ++ ++ /* Check window for sanity */ ++ if ((uint8)(txmax - bus->tx_seq) > 0x40) { ++ AP6211_ERR("%s: got unlikely tx max %d with tx_seq %d\n", ++ __FUNCTION__, txmax, bus->tx_seq); ++ txmax = bus->tx_max; ++ } ++ bus->tx_max = txmax; ++ ++ /* Remove superframe header, remember offset */ ++ PKTPULL(osh, pfirst, doff); ++ sfdoff = doff; ++ ++ /* Validate all the subframe headers */ ++ for (num = 0, pnext = pfirst; pnext && !errcode; ++ num++, pnext = PKTNEXT(osh, pnext)) { ++ dptr = (uint8 *)PKTDATA(osh, pnext); ++ dlen = (uint16)PKTLEN(osh, pnext); ++ sublen = ltoh16_ua(dptr); ++ check = ltoh16_ua(dptr + sizeof(uint16)); ++ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); ++ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); ++#ifdef DHD_DEBUG ++ if (DHD_GLOM_ON()) { ++ prhex("subframe", dptr, 32); ++ } ++#endif ++ ++ if ((uint16)~(sublen^check)) { ++ AP6211_ERR("%s (subframe %d): HW hdr error: " ++ "len/check 0x%04x/0x%04x\n", ++ __FUNCTION__, num, sublen, check); ++ errcode = -1; ++ } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN_RX)) { ++ AP6211_ERR("%s (subframe %d): length mismatch: " ++ "len 0x%04x, expect 0x%04x\n", ++ __FUNCTION__, num, sublen, dlen); ++ errcode = -1; ++ } else if ((chan != SDPCM_DATA_CHANNEL) && ++ (chan != SDPCM_EVENT_CHANNEL)) { ++ AP6211_ERR("%s (subframe %d): bad channel %d\n", ++ __FUNCTION__, num, chan); ++ errcode = -1; ++ } else if ((doff < SDPCM_HDRLEN_RX) || (doff > sublen)) { ++ AP6211_ERR("%s (subframe %d): Bad data offset %d: HW %d min %d\n", ++ __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN_RX); ++ errcode = -1; ++ } ++ } ++ ++ if (errcode) { ++ /* Terminate frame on error, request a couple retries */ ++ if (bus->glomerr++ < 3) { ++ /* Restore superframe header space */ ++ PKTPUSH(osh, pfirst, sfdoff); ++ dhdsdio_rxfail(bus, TRUE, TRUE); ++ } else { ++ bus->glomerr = 0; ++ dhdsdio_rxfail(bus, TRUE, FALSE); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(osh, bus->glom, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ bus->rxglomfail++; ++ bus->glom = NULL; ++ } ++ bus->nextlen = 0; ++ return 0; ++ } ++ ++ /* Basic SD framing looks ok - process each packet (header) */ ++ bus->glom = NULL; ++ plast = NULL; ++ ++ dhd_os_sdlock_rxq(bus->dhd); ++ for (num = 0; pfirst; rxseq++, pfirst = pnext) { ++ pnext = PKTNEXT(osh, pfirst); ++ PKTSETNEXT(osh, pfirst, NULL); ++ ++ dptr = (uint8 *)PKTDATA(osh, pfirst); ++ sublen = ltoh16_ua(dptr); ++ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); ++ seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); ++ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); ++ ++ AP6211_DEBUG("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n", ++ __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst), ++ PKTLEN(osh, pfirst), sublen, chan, seq); ++ ++ ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL)); ++ ++ if (rxseq != seq) { ++ AP6211_DEBUG("%s: rx_seq %d, expected %d\n", ++ __FUNCTION__, seq, rxseq); ++ bus->rx_badseq++; ++ rxseq = seq; ++ } ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_DATA_ON()) { ++ prhex("Rx Subframe Data", dptr, dlen); ++ } ++#endif ++ ++ PKTSETLEN(osh, pfirst, sublen); ++ PKTPULL(osh, pfirst, doff); ++ ++ reorder_info_len = sizeof(reorder_info_buf); ++ ++ if (PKTLEN(osh, pfirst) == 0) { ++ PKTFREE(bus->dhd->osh, pfirst, FALSE); ++ continue; ++ } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf, ++ &reorder_info_len) != 0) { ++ AP6211_ERR("%s: rx protocol error\n", __FUNCTION__); ++ bus->dhd->rx_errors++; ++ PKTFREE(osh, pfirst, FALSE); ++ continue; ++ } ++ if (reorder_info_len) { ++ uint32 free_buf_count; ++ void *ppfirst; ++ ++ ppfirst = pfirst; ++ /* Reordering info from the firmware */ ++ dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, ++ reorder_info_len, &ppfirst, &free_buf_count); ++ ++ if (free_buf_count == 0) { ++ continue; ++ } ++ else { ++ void *temp; ++ ++ /* go to the end of the chain and attach the pnext there */ ++ temp = ppfirst; ++ while (PKTNEXT(osh, temp) != NULL) { ++ temp = PKTNEXT(osh, temp); ++ } ++ pfirst = temp; ++ if (list_tail[ifidx] == NULL) { ++ list_head[ifidx] = ppfirst; ++ list_tail[ifidx] = pfirst; ++ } ++ else { ++ PKTSETNEXT(osh, list_tail[ifidx], ppfirst); ++ list_tail[ifidx] = pfirst; ++ } ++ } ++ ++ num += (uint8)free_buf_count; ++ } ++ else { ++ /* this packet will go up, link back into chain and count it */ ++ ++ if (list_tail[ifidx] == NULL) { ++ list_head[ifidx] = list_tail[ifidx] = pfirst; ++ } ++ else { ++ PKTSETNEXT(osh, list_tail[ifidx], pfirst); ++ list_tail[ifidx] = pfirst; ++ } ++ num++; ++ } ++#ifdef DHD_DEBUG ++ if (DHD_GLOM_ON()) { ++ AP6211_DEBUG("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n", ++ __FUNCTION__, num, pfirst, ++ PKTDATA(osh, pfirst), PKTLEN(osh, pfirst), ++ PKTNEXT(osh, pfirst), PKTLINK(pfirst)); ++ prhex("", (uint8 *)PKTDATA(osh, pfirst), ++ MIN(PKTLEN(osh, pfirst), 32)); ++ } ++#endif /* DHD_DEBUG */ ++ } ++ dhd_os_sdunlock_rxq(bus->dhd); ++ ++ for (idx = 0; idx < DHD_MAX_IFS; idx++) { ++ if (list_head[idx]) { ++ void *temp; ++ uint8 cnt = 0; ++ temp = list_head[idx]; ++ do { ++ temp = PKTNEXT(osh, temp); ++ cnt++; ++ } while (temp); ++ if (cnt) { ++ dhd_os_sdunlock(bus->dhd); ++ dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0); ++ dhd_os_sdlock(bus->dhd); ++ } ++ } ++ } ++ bus->rxglomframes++; ++ bus->rxglompkts += num; ++ } ++ return num; ++} ++ ++ ++/* Return TRUE if there may be more frames to read */ ++static uint ++dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) ++{ ++ osl_t *osh = bus->dhd->osh; ++ bcmsdh_info_t *sdh = bus->sdh; ++ ++ uint16 len, check; /* Extracted hardware header fields */ ++ uint8 chan, seq, doff; /* Extracted software header fields */ ++ uint8 fcbits; /* Extracted fcbits from software header */ ++ uint8 delta; ++ ++ void *pkt; /* Packet for event or data frames */ ++ uint16 pad; /* Number of pad bytes to read */ ++ uint16 rdlen; /* Total number of bytes to read */ ++ uint8 rxseq; /* Next sequence number to expect */ ++ uint rxleft = 0; /* Remaining number of frames allowed */ ++ int sdret; /* Return code from bcmsdh calls */ ++ uint8 txmax; /* Maximum tx sequence offered */ ++ bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */ ++ uint8 *rxbuf; ++ int ifidx = 0; ++ uint rxcount = 0; /* Total frames read */ ++ uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; ++ uint reorder_info_len; ++ uint pkt_count; ++ ++#if defined(DHD_DEBUG) || defined(SDTEST) ++ bool sdtest = FALSE; /* To limit message spew from test mode */ ++#endif ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ bus->readframes = TRUE; ++ ++ if (!KSO_ENAB(bus)) { ++ AP6211_DEBUG("%s: KSO off\n", __FUNCTION__); ++ bus->readframes = FALSE; ++ return 0; ++ } ++ ++ ASSERT(maxframes); ++ ++#ifdef SDTEST ++ /* Allow pktgen to override maxframes */ ++ if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) { ++ maxframes = bus->pktgen_count; ++ sdtest = TRUE; ++ } ++#endif ++ ++ /* Not finished unless we encounter no more frames indication */ ++ *finished = FALSE; ++ ++ ++ for (rxseq = bus->rx_seq, rxleft = maxframes; ++ !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN; ++ rxseq++, rxleft--) { ++ ++#ifdef DHDTHREAD ++ /* terence: fix got unlikely tx max for 43362a0*/ ++ if (bus->sih->chip!=BCM43362_CHIP_ID && bus->sih->chiprev!=BCM43362A0_CHIP_REV) { ++ /* tx more to improve rx performance */ ++ if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && ++ pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) { ++ dhdsdio_sendfromq(bus, dhd_txbound); ++ } ++ } ++#endif /* DHDTHREAD */ ++ ++ /* Handle glomming separately */ ++ if (bus->glom || bus->glomd) { ++ uint8 cnt; ++ AP6211_DEBUG("%s: calling rxglom: glomd %p, glom %p\n", ++ __FUNCTION__, bus->glomd, bus->glom); ++ cnt = dhdsdio_rxglom(bus, rxseq); ++ AP6211_DEBUG("%s: rxglom returned %d\n", __FUNCTION__, cnt); ++ rxseq += cnt - 1; ++ rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; ++ continue; ++ } ++ ++ /* Try doing single read if we can */ ++ if (dhd_readahead && bus->nextlen) { ++ uint16 nextlen = bus->nextlen; ++ bus->nextlen = 0; ++ ++ if (bus->bus == SPI_BUS) { ++ rdlen = len = nextlen; ++ } ++ else { ++ rdlen = len = nextlen << 4; ++ ++ /* Pad read to blocksize for efficiency */ ++ if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { ++ pad = bus->blocksize - (rdlen % bus->blocksize); ++ if ((pad <= bus->roundup) && (pad < bus->blocksize) && ++ ((rdlen + pad + firstread) < MAX_RX_DATASZ)) ++ rdlen += pad; ++ } else if (rdlen % DHD_SDALIGN) { ++ rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); ++ } ++ } ++ ++ /* We use bus->rxctl buffer in WinXP for initial control pkt receives. ++ * Later we use buffer-poll for data as well as control packets. ++ * This is required because dhd receives full frame in gSPI unlike SDIO. ++ * After the frame is received we have to distinguish whether it is data ++ * or non-data frame. ++ */ ++ /* Allocate a packet buffer */ ++ dhd_os_sdlock_rxq(bus->dhd); ++ if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) { ++ if (bus->bus == SPI_BUS) { ++ bus->usebufpool = FALSE; ++ bus->rxctl = bus->rxbuf; ++ if (dhd_alignctl) { ++ bus->rxctl += firstread; ++ if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) ++ bus->rxctl += (DHD_SDALIGN - pad); ++ bus->rxctl -= firstread; ++ } ++ ASSERT(bus->rxctl >= bus->rxbuf); ++ rxbuf = bus->rxctl; ++ /* Read the entire frame */ ++ sdret = dhd_bcmsdh_recv_buf(bus, ++ bcmsdh_cur_sbwad(sdh), ++ SDIO_FUNC_2, ++ F2SYNC, rxbuf, rdlen, ++ NULL, NULL, NULL); ++ bus->f2rxdata++; ++ ASSERT(sdret != BCME_PENDING); ++ ++ ++ /* Control frame failures need retransmission */ ++ if (sdret < 0) { ++ AP6211_ERR("%s: read %d control bytes failed: %d\n", ++ __FUNCTION__, rdlen, sdret); ++ /* dhd.rx_ctlerrs is higher level */ ++ bus->rxc_errors++; ++ dhd_os_sdunlock_rxq(bus->dhd); ++ dhdsdio_rxfail(bus, TRUE, ++ (bus->bus == SPI_BUS) ? FALSE : TRUE); ++ continue; ++ } ++ } else { ++ /* Give up on data, request rtx of events */ ++ AP6211_ERR("%s (nextlen): PKTGET failed: len %d rdlen %d " ++ "expected rxseq %d\n", ++ __FUNCTION__, len, rdlen, rxseq); ++ /* Just go try again w/normal header read */ ++ dhd_os_sdunlock_rxq(bus->dhd); ++ continue; ++ } ++ } else { ++ if (bus->bus == SPI_BUS) ++ bus->usebufpool = TRUE; ++ ++ ASSERT(!PKTLINK(pkt)); ++ PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); ++ rxbuf = (uint8 *)PKTDATA(osh, pkt); ++ /* Read the entire frame */ ++ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), ++ SDIO_FUNC_2, ++ F2SYNC, rxbuf, rdlen, ++ pkt, NULL, NULL); ++ bus->f2rxdata++; ++ ASSERT(sdret != BCME_PENDING); ++ ++ if (sdret < 0) { ++ AP6211_ERR("%s (nextlen): read %d bytes failed: %d\n", ++ __FUNCTION__, rdlen, sdret); ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++ bus->dhd->rx_errors++; ++ dhd_os_sdunlock_rxq(bus->dhd); ++ /* Force retry w/normal header read. Don't attempt NAK for ++ * gSPI ++ */ ++ dhdsdio_rxfail(bus, TRUE, ++ (bus->bus == SPI_BUS) ? FALSE : TRUE); ++ continue; ++ } ++ } ++ dhd_os_sdunlock_rxq(bus->dhd); ++ ++ /* Now check the header */ ++ bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN_RX); ++ ++ /* Extract hardware header fields */ ++ len = ltoh16_ua(bus->rxhdr); ++ check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); ++ ++ /* All zeros means readahead info was bad */ ++ if (!(len|check)) { ++ AP6211_DEBUG("%s (nextlen): read zeros in HW header???\n", ++ __FUNCTION__); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ GSPI_PR55150_BAILOUT; ++ continue; ++ } ++ ++ /* Validate check bytes */ ++ if ((uint16)~(len^check)) { ++ AP6211_ERR("%s (nextlen): HW hdr error: nextlen/len/check" ++ " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen, ++ len, check); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ bus->rx_badhdr++; ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ GSPI_PR55150_BAILOUT; ++ continue; ++ } ++ ++ /* Validate frame length */ ++ if (len < SDPCM_HDRLEN_RX) { ++ AP6211_ERR("%s (nextlen): HW hdr length invalid: %d\n", ++ __FUNCTION__, len); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ GSPI_PR55150_BAILOUT; ++ continue; ++ } ++ ++ /* Check for consistency with readahead info */ ++ len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4)); ++ if (len_consistent) { ++ /* Mismatch, force retry w/normal header (may be >4K) */ ++ AP6211_ERR("%s (nextlen): mismatch, nextlen %d len %d rnd %d; " ++ "expected rxseq %d\n", ++ __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE); ++ GSPI_PR55150_BAILOUT; ++ continue; ++ } ++ ++ ++ /* Extract software header fields */ ++ chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ ++ bus->nextlen = ++ bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; ++ if ((bus->nextlen << 4) > MAX_RX_DATASZ) { ++ AP6211_DEBUG("%s (nextlen): got frame w/nextlen too large" ++ " (%d), seq %d\n", __FUNCTION__, bus->nextlen, ++ seq); ++ bus->nextlen = 0; ++ } ++ ++ bus->dhd->rx_readahead_cnt ++; ++ /* Handle Flow Control */ ++ fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ ++ delta = 0; ++ if (~bus->flowcontrol & fcbits) { ++ bus->fc_xoff++; ++ delta = 1; ++ } ++ if (bus->flowcontrol & ~fcbits) { ++ bus->fc_xon++; ++ delta = 1; ++ } ++ ++ if (delta) { ++ bus->fc_rcvd++; ++ bus->flowcontrol = fcbits; ++ } ++ ++ /* Check and update sequence number */ ++ if (rxseq != seq) { ++ AP6211_DEBUG("%s (nextlen): rx_seq %d, expected %d\n", ++ __FUNCTION__, seq, rxseq); ++ bus->rx_badseq++; ++ rxseq = seq; ++ } ++ ++ /* Check window for sanity */ ++ if ((uint8)(txmax - bus->tx_seq) > 0x40) { ++ AP6211_ERR("%s: got unlikely tx max %d with tx_seq %d\n", ++ __FUNCTION__, txmax, bus->tx_seq); ++ txmax = bus->tx_max; ++ } ++ bus->tx_max = txmax; ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_DATA_ON()) { ++ prhex("Rx Data", rxbuf, len); ++ } else if (DHD_HDRS_ON()) { ++ prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX); ++ } ++#endif ++ ++ if (chan == SDPCM_CONTROL_CHANNEL) { ++ if (bus->bus == SPI_BUS) { ++ dhdsdio_read_control(bus, rxbuf, len, doff); ++ if (bus->usebufpool) { ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ } ++ continue; ++ } else { ++ AP6211_ERR("%s (nextlen): readahead on control" ++ " packet %d?\n", __FUNCTION__, seq); ++ /* Force retry w/normal header read */ ++ bus->nextlen = 0; ++ dhdsdio_rxfail(bus, FALSE, TRUE); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ continue; ++ } ++ } ++ ++ if ((bus->bus == SPI_BUS) && !bus->usebufpool) { ++ AP6211_ERR("Received %d bytes on %d channel. Running out of " ++ "rx pktbuf's or not yet malloced.\n", len, chan); ++ continue; ++ } ++ ++ /* Validate data offset */ ++ if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) { ++ AP6211_ERR("%s (nextlen): bad data offset %d: HW len %d min %d\n", ++ __FUNCTION__, doff, len, SDPCM_HDRLEN_RX); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ ASSERT(0); ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ continue; ++ } ++ ++ /* All done with this one -- now deliver the packet */ ++ goto deliver; ++ } ++ /* gSPI frames should not be handled in fractions */ ++ if (bus->bus == SPI_BUS) { ++ break; ++ } ++ ++ /* Read frame header (hardware and software) */ ++ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ bus->rxhdr, firstread, NULL, NULL, NULL); ++ bus->f2rxhdrs++; ++ ASSERT(sdret != BCME_PENDING); ++ ++ if (sdret < 0) { ++ AP6211_ERR("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret); ++ bus->rx_hdrfail++; ++ dhdsdio_rxfail(bus, TRUE, TRUE); ++ continue; ++ } ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() || DHD_HDRS_ON()) { ++ prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX); ++ } ++#endif ++ ++ /* Extract hardware header fields */ ++ len = ltoh16_ua(bus->rxhdr); ++ check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); ++ ++ /* All zeros means no more frames */ ++ if (!(len|check)) { ++ *finished = TRUE; ++ break; ++ } ++ ++ /* Validate check bytes */ ++ if ((uint16)~(len^check)) { ++ AP6211_ERR("%s: HW hdr error: len/check 0x%04x/0x%04x\n", ++ __FUNCTION__, len, check); ++ bus->rx_badhdr++; ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ continue; ++ } ++ ++ /* Validate frame length */ ++ if (len < SDPCM_HDRLEN_RX) { ++ AP6211_ERR("%s: HW hdr length invalid: %d\n", __FUNCTION__, len); ++ continue; ++ } ++ ++ /* Extract software header fields */ ++ chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ ++ /* Validate data offset */ ++ if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) { ++ AP6211_ERR("%s: Bad data offset %d: HW len %d, min %d seq %d\n", ++ __FUNCTION__, doff, len, SDPCM_HDRLEN_RX, seq); ++ bus->rx_badhdr++; ++ ASSERT(0); ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ continue; ++ } ++ ++ /* Save the readahead length if there is one */ ++ bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; ++ if ((bus->nextlen << 4) > MAX_RX_DATASZ) { ++ AP6211_DEBUG("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n", ++ __FUNCTION__, bus->nextlen, seq); ++ bus->nextlen = 0; ++ } ++ ++ /* Handle Flow Control */ ++ fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ ++ delta = 0; ++ if (~bus->flowcontrol & fcbits) { ++ bus->fc_xoff++; ++ delta = 1; ++ } ++ if (bus->flowcontrol & ~fcbits) { ++ bus->fc_xon++; ++ delta = 1; ++ } ++ ++ if (delta) { ++ bus->fc_rcvd++; ++ bus->flowcontrol = fcbits; ++ } ++ ++ /* Check and update sequence number */ ++ if (rxseq != seq) { ++ AP6211_DEBUG("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq); ++ bus->rx_badseq++; ++ rxseq = seq; ++ } ++ ++ /* Check window for sanity */ ++ if ((uint8)(txmax - bus->tx_seq) > 0x40) { ++ AP6211_ERR("%s: got unlikely tx max %d with tx_seq %d\n", ++ __FUNCTION__, txmax, bus->tx_seq); ++ txmax = bus->tx_max; ++ } ++ bus->tx_max = txmax; ++ ++ /* Call a separate function for control frames */ ++ if (chan == SDPCM_CONTROL_CHANNEL) { ++ dhdsdio_read_control(bus, bus->rxhdr, len, doff); ++ continue; ++ } ++ ++ ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) || ++ (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL)); ++ ++ /* Length to read */ ++ rdlen = (len > firstread) ? (len - firstread) : 0; ++ ++ /* May pad read to blocksize for efficiency */ ++ if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { ++ pad = bus->blocksize - (rdlen % bus->blocksize); ++ if ((pad <= bus->roundup) && (pad < bus->blocksize) && ++ ((rdlen + pad + firstread) < MAX_RX_DATASZ)) ++ rdlen += pad; ++ } else if (rdlen % DHD_SDALIGN) { ++ rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); ++ } ++ ++ /* Satisfy length-alignment requirements */ ++ if (forcealign && (rdlen & (ALIGNMENT - 1))) ++ rdlen = ROUNDUP(rdlen, ALIGNMENT); ++ ++ if ((rdlen + firstread) > MAX_RX_DATASZ) { ++ /* Too long -- skip this frame */ ++ AP6211_ERR("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen); ++ bus->dhd->rx_errors++; bus->rx_toolong++; ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ continue; ++ } ++ ++ dhd_os_sdlock_rxq(bus->dhd); ++ if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) { ++ /* Give up on data, request rtx of events */ ++ AP6211_ERR("%s: PKTGET failed: rdlen %d chan %d\n", ++ __FUNCTION__, rdlen, chan); ++ bus->dhd->rx_dropped++; ++ dhd_os_sdunlock_rxq(bus->dhd); ++ dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan)); ++ continue; ++ } ++ dhd_os_sdunlock_rxq(bus->dhd); ++ ++ ASSERT(!PKTLINK(pkt)); ++ ++ /* Leave room for what we already read, and align remainder */ ++ ASSERT(firstread < (PKTLEN(osh, pkt))); ++ PKTPULL(osh, pkt, firstread); ++ PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); ++ ++ /* Read the remaining frame data */ ++ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL); ++ bus->f2rxdata++; ++ ASSERT(sdret != BCME_PENDING); ++ ++ if (sdret < 0) { ++ AP6211_ERR("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen, ++ ((chan == SDPCM_EVENT_CHANNEL) ? "event" : ++ ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ bus->dhd->rx_errors++; ++ dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan)); ++ continue; ++ } ++ ++ /* Copy the already-read portion */ ++ PKTPUSH(osh, pkt, firstread); ++ bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread); ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_DATA_ON()) { ++ prhex("Rx Data", PKTDATA(osh, pkt), len); ++ } ++#endif ++ ++deliver: ++ /* Save superframe descriptor and allocate packet frame */ ++ if (chan == SDPCM_GLOM_CHANNEL) { ++ if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { ++ AP6211_DEBUG("%s: got glom descriptor, %d bytes:\n", ++ __FUNCTION__, len); ++#ifdef DHD_DEBUG ++ if (DHD_GLOM_ON()) { ++ prhex("Glom Data", PKTDATA(osh, pkt), len); ++ } ++#endif ++ PKTSETLEN(osh, pkt, len); ++ ASSERT(doff == SDPCM_HDRLEN_RX); ++ PKTPULL(osh, pkt, SDPCM_HDRLEN_RX); ++ bus->glomd = pkt; ++ } else { ++ AP6211_ERR("%s: glom superframe w/o descriptor!\n", __FUNCTION__); ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ } ++ continue; ++ } ++ ++ /* Fill in packet len and prio, deliver upward */ ++ PKTSETLEN(osh, pkt, len); ++ PKTPULL(osh, pkt, doff); ++ ++#ifdef SDTEST ++ /* Test channel packets are processed separately */ ++ if (chan == SDPCM_TEST_CHANNEL) { ++ dhdsdio_testrcv(bus, pkt, seq); ++ continue; ++ } ++#endif /* SDTEST */ ++ ++ if (PKTLEN(osh, pkt) == 0) { ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ continue; ++ } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf, ++ &reorder_info_len) != 0) { ++ AP6211_ERR("%s: rx protocol error\n", __FUNCTION__); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ bus->dhd->rx_errors++; ++ continue; ++ } ++ if (reorder_info_len) { ++ /* Reordering info from the firmware */ ++ dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len, ++ &pkt, &pkt_count); ++ if (pkt_count == 0) ++ continue; ++ } ++ else ++ pkt_count = 1; ++ ++ ++ /* Unlock during rx call */ ++ dhd_os_sdunlock(bus->dhd); ++ dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan); ++ dhd_os_sdlock(bus->dhd); ++ } ++ rxcount = maxframes - rxleft; ++#ifdef DHD_DEBUG ++ /* Message if we hit the limit */ ++ if (!rxleft && !sdtest) ++ AP6211_DEBUG("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes); ++ else ++#endif /* DHD_DEBUG */ ++ AP6211_DEBUG("%s: processed %d frames\n", __FUNCTION__, rxcount); ++ /* Back off rxseq if awaiting rtx, update rx_seq */ ++ if (bus->rxskip) ++ rxseq--; ++ bus->rx_seq = rxseq; ++ ++ if (bus->reqbussleep) ++ { ++ dhdsdio_bussleep(bus, TRUE); ++ bus->reqbussleep = FALSE; ++ } ++ bus->readframes = FALSE; ++ ++ return rxcount; ++} ++ ++static uint32 ++dhdsdio_hostmail(dhd_bus_t *bus) ++{ ++ sdpcmd_regs_t *regs = bus->regs; ++ uint32 intstatus = 0; ++ uint32 hmb_data; ++ uint8 fcbits; ++ uint retries = 0; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ /* Read mailbox data and ack that we did so */ ++ R_SDREG(hmb_data, ®s->tohostmailboxdata, retries); ++ if (retries <= retry_limit) ++ W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries); ++ bus->f1regdata += 2; ++ ++ /* Dongle recomposed rx frames, accept them again */ ++ if (hmb_data & HMB_DATA_NAKHANDLED) { ++ AP6211_DEBUG("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq); ++ if (!bus->rxskip) { ++ AP6211_ERR("%s: unexpected NAKHANDLED!\n", __FUNCTION__); ++ } ++ bus->rxskip = FALSE; ++ intstatus |= FRAME_AVAIL_MASK(bus); ++ } ++ ++ /* ++ * DEVREADY does not occur with gSPI. ++ */ ++ if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) { ++ bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT; ++ if (bus->sdpcm_ver != SDPCM_PROT_VERSION) ++ AP6211_ERR("Version mismatch, dongle reports %d, expecting %d\n", ++ bus->sdpcm_ver, SDPCM_PROT_VERSION); ++ else ++ AP6211_ERR("Dongle ready, protocol version %d\n", bus->sdpcm_ver); ++ /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */ ++ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && ++ (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) { ++ uint32 val; ++ ++ val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); ++ val &= ~CC_XMTDATAAVAIL_MODE; ++ val |= CC_XMTDATAAVAIL_CTRL; ++ W_REG(bus->dhd->osh, &bus->regs->corecontrol, val); ++ ++ val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); ++ } ++ ++#ifdef DHD_DEBUG ++ /* Retrieve console state address now that firmware should have updated it */ ++ { ++ sdpcm_shared_t shared; ++ if (dhdsdio_readshared(bus, &shared) == 0) ++ bus->console_addr = shared.console_addr; ++ } ++#endif /* DHD_DEBUG */ ++ } ++ ++ /* ++ * Flow Control has been moved into the RX headers and this out of band ++ * method isn't used any more. Leave this here for possibly remaining backward ++ * compatible with older dongles ++ */ ++ if (hmb_data & HMB_DATA_FC) { ++ fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT; ++ ++ if (fcbits & ~bus->flowcontrol) ++ bus->fc_xoff++; ++ if (bus->flowcontrol & ~fcbits) ++ bus->fc_xon++; ++ ++ bus->fc_rcvd++; ++ bus->flowcontrol = fcbits; ++ } ++ ++#ifdef DHD_DEBUG ++ /* At least print a message if FW halted */ ++ if (hmb_data & HMB_DATA_FWHALT) { ++ AP6211_ERR("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"); ++ dhdsdio_checkdied(bus, NULL, 0); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ } ++#endif /* DHD_DEBUG */ ++ ++ /* Shouldn't be any others */ ++ if (hmb_data & ~(HMB_DATA_DEVREADY | ++ HMB_DATA_FWHALT | ++ HMB_DATA_NAKHANDLED | ++ HMB_DATA_FC | ++ HMB_DATA_FWREADY | ++ HMB_DATA_FCDATA_MASK | ++ HMB_DATA_VERSION_MASK)) { ++ AP6211_ERR("Unknown mailbox data content: 0x%02x\n", hmb_data); ++ } ++ ++ return intstatus; ++} ++ ++static bool ++dhdsdio_dpc(dhd_bus_t *bus) ++{ ++ bcmsdh_info_t *sdh = bus->sdh; ++ sdpcmd_regs_t *regs = bus->regs; ++ uint32 intstatus, newstatus = 0; ++ uint retries = 0; ++ uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */ ++ uint txlimit = dhd_txbound; /* Tx frames to send before resched */ ++ uint framecnt = 0; /* Temporary counter of tx/rx frames */ ++ bool rxdone = TRUE; /* Flag for no more read data */ ++ bool resched = FALSE; /* Flag indicating resched wanted */ ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (bus->dhd->busstate == DHD_BUS_DOWN) { ++ AP6211_ERR("%s: Bus down, ret\n", __FUNCTION__); ++ bus->intstatus = 0; ++ return 0; ++ } ++ ++ /* Start with leftover status bits */ ++ intstatus = bus->intstatus; ++ ++ dhd_os_sdlock(bus->dhd); ++ ++ if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) { ++ AP6211_ERR("%s: Device asleep\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ /* If waiting for HTAVAIL, check status */ ++ if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) { ++ int err; ++ uint8 clkctl, devctl = 0; ++ ++#ifdef DHD_DEBUG ++ /* Check for inconsistent device control */ ++ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); ++ if (err) { ++ AP6211_ERR("%s: error reading DEVCTL: %d\n", __FUNCTION__, err); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ } else { ++ ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY); ++ } ++#endif /* DHD_DEBUG */ ++ ++ /* Read CSR, if clock on switch to AVAIL, else ignore */ ++ clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if (err) { ++ AP6211_ERR("%s: error reading CSR: %d\n", __FUNCTION__, err); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ } ++ ++ AP6211_DEBUG("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl); ++ ++ if (SBSDIO_HTAV(clkctl)) { ++ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); ++ if (err) { ++ AP6211_ERR("%s: error reading DEVCTL: %d\n", ++ __FUNCTION__, err); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ } ++ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); ++ if (err) { ++ AP6211_ERR("%s: error writing DEVCTL: %d\n", ++ __FUNCTION__, err); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ } ++ bus->clkstate = CLK_AVAIL; ++ } else { ++ goto clkwait; ++ } ++ } ++ ++ BUS_WAKE(bus); ++ ++ /* Make sure backplane clock is on */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); ++ if (bus->clkstate != CLK_AVAIL) ++ goto clkwait; ++ ++ /* Pending interrupt indicates new device status */ ++ if (bus->ipend) { ++ bus->ipend = FALSE; ++ R_SDREG(newstatus, ®s->intstatus, retries); ++ bus->f1regdata++; ++ if (bcmsdh_regfail(bus->sdh)) ++ newstatus = 0; ++ newstatus &= bus->hostintmask; ++ bus->fcstate = !!(newstatus & I_HMB_FC_STATE); ++ if (newstatus) { ++ bus->f1regdata++; ++ if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) && ++ (newstatus == I_XMTDATA_AVAIL)) { ++ } ++ else ++ W_SDREG(newstatus, ®s->intstatus, retries); ++ } ++ } ++ ++ /* Merge new bits with previous */ ++ intstatus |= newstatus; ++ bus->intstatus = 0; ++ ++ /* Handle flow-control change: read new state in case our ack ++ * crossed another change interrupt. If change still set, assume ++ * FC ON for safety, let next loop through do the debounce. ++ */ ++ if (intstatus & I_HMB_FC_CHANGE) { ++ intstatus &= ~I_HMB_FC_CHANGE; ++ W_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries); ++ R_SDREG(newstatus, ®s->intstatus, retries); ++ bus->f1regdata += 2; ++ bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); ++ intstatus |= (newstatus & bus->hostintmask); ++ } ++ ++ /* Just being here means nothing more to do for chipactive */ ++ if (intstatus & I_CHIPACTIVE) { ++ /* ASSERT(bus->clkstate == CLK_AVAIL); */ ++ intstatus &= ~I_CHIPACTIVE; ++ } ++ ++ /* Handle host mailbox indication */ ++ if (intstatus & I_HMB_HOST_INT) { ++ intstatus &= ~I_HMB_HOST_INT; ++ intstatus |= dhdsdio_hostmail(bus); ++ } ++ ++ /* Generally don't ask for these, can get CRC errors... */ ++ if (intstatus & I_WR_OOSYNC) { ++ AP6211_DEBUG("Dongle reports WR_OOSYNC\n"); ++ intstatus &= ~I_WR_OOSYNC; ++ } ++ ++ if (intstatus & I_RD_OOSYNC) { ++ AP6211_DEBUG("Dongle reports RD_OOSYNC\n"); ++ intstatus &= ~I_RD_OOSYNC; ++ } ++ ++ if (intstatus & I_SBINT) { ++ AP6211_DEBUG("Dongle reports SBINT\n"); ++ intstatus &= ~I_SBINT; ++ } ++ ++ /* Would be active due to wake-wlan in gSPI */ ++ if (intstatus & I_CHIPACTIVE) { ++ AP6211_DEBUG("Dongle reports CHIPACTIVE\n"); ++ intstatus &= ~I_CHIPACTIVE; ++ } ++ ++ /* Ignore frame indications if rxskip is set */ ++ if (bus->rxskip) { ++ intstatus &= ~FRAME_AVAIL_MASK(bus); ++ } ++ ++ /* On frame indication, read available frames */ ++ if (PKT_AVAILABLE(bus, intstatus)) { ++ framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone); ++ if (rxdone || bus->rxskip) ++ intstatus &= ~FRAME_AVAIL_MASK(bus); ++ rxlimit -= MIN(framecnt, rxlimit); ++ } ++ ++ /* Keep still-pending events for next scheduling */ ++ bus->intstatus = intstatus; ++ ++clkwait: ++ /* Re-enable interrupts to detect new device events (mailbox, rx frame) ++ * or clock availability. (Allows tx loop to check ipend if desired.) ++ * (Unless register access seems hosed, as we may not be able to ACK...) ++ */ ++ if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) { ++ AP6211_DEBUG("%s: enable SDIO interrupts, rxdone %d framecnt %d\n", ++ __FUNCTION__, rxdone, framecnt); ++ bus->intdis = FALSE; ++#if defined(OOB_INTR_ONLY) ++ bcmsdh_oob_intr_set(1); ++#endif /* defined(OOB_INTR_ONLY) */ ++ bcmsdh_intr_enable(sdh); ++ } ++ ++#if defined(OOB_INTR_ONLY) && !defined(HW_OOB) ++ /* In case of SW-OOB(using edge trigger), ++ * Check interrupt status in the dongle again after enable irq on the host. ++ * and rechedule dpc if interrupt is pended in the dongle. ++ * There is a chance to miss OOB interrupt while irq is disabled on the host. ++ * No need to do this with HW-OOB(level trigger) ++ */ ++ R_SDREG(newstatus, ®s->intstatus, retries); ++ if (bcmsdh_regfail(bus->sdh)) ++ newstatus = 0; ++ if (newstatus & bus->hostintmask) { ++ bus->ipend = TRUE; ++ resched = TRUE; ++ } ++#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */ ++#ifdef PROP_TXSTATUS ++ dhd_wlfc_trigger_pktcommit(bus->dhd); ++#endif ++ if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { ++ int ret, i; ++ ++ uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN; ++ ++ if (*frame_seq != bus->tx_seq) { ++ AP6211_DEBUG("%s IOCTL frame seq lag detected!" ++ " frm_seq:%d != bus->tx_seq:%d, corrected\n", ++ __FUNCTION__, *frame_seq, bus->tx_seq); ++ *frame_seq = bus->tx_seq; ++ } ++ ++ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len, ++ NULL, NULL, NULL); ++ ASSERT(ret != BCME_PENDING); ++ if (ret == BCME_NODEVICE) { ++ AP6211_ERR("%s: Device asleep already\n", __FUNCTION__); ++ } else if (ret < 0) { ++ /* On failure, abort the command and terminate the frame */ ++ AP6211_DEBUG("%s: sdio error %d, abort command and terminate frame.\n", ++ __FUNCTION__, ret); ++ bus->tx_sderrs++; ++ ++ bcmsdh_abort(sdh, SDIO_FUNC_2); ++ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, ++ SFC_WF_TERM, NULL); ++ bus->f1regdata++; ++ ++ for (i = 0; i < 3; i++) { ++ uint8 hi, lo; ++ hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCHI, NULL); ++ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_WFRAMEBCLO, NULL); ++ bus->f1regdata += 2; ++ if ((hi == 0) && (lo == 0)) ++ break; ++ } ++ } ++ if (ret == 0) { ++ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; ++ } ++ ++ bus->ctrl_frame_stat = FALSE; ++ dhd_wait_event_wakeup(bus->dhd); ++ } ++ /* Send queued frames (limit 1 if rx may still be pending) */ ++ else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && ++ pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) { ++ framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax); ++ framecnt = dhdsdio_sendfromq(bus, framecnt); ++ txlimit -= framecnt; ++ } ++ /* Resched the DPC if ctrl cmd is pending on bus credit */ ++ if (bus->ctrl_frame_stat) ++ resched = TRUE; ++ ++ /* Resched if events or tx frames are pending, else await next interrupt */ ++ /* On failed register access, all bets are off: no resched or interrupts */ ++ if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) { ++ if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) & ++ SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { ++ /* Bus failed because of KSO */ ++ AP6211_ERR("%s: Bus failed due to KSO\n", __FUNCTION__); ++ bus->kso = FALSE; ++ } else { ++ AP6211_ERR("%s: failed backplane access over SDIO, halting operation\n", ++ __FUNCTION__); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ bus->intstatus = 0; ++ } ++ } else if (bus->clkstate == CLK_PENDING) { ++ /* Awaiting I_CHIPACTIVE; don't resched */ ++ } else if (bus->intstatus || bus->ipend || ++ (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) || ++ PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */ ++ resched = TRUE; ++ } ++ ++ bus->dpc_sched = resched; ++ ++ /* If we're done for now, turn off clock request. */ ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) { ++ bus->activity = FALSE; ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ } ++ ++exit: ++ dhd_os_sdunlock(bus->dhd); ++ return resched; ++} ++ ++bool ++dhd_bus_dpc(struct dhd_bus *bus) ++{ ++ bool resched; ++ ++ /* Call the DPC directly. */ ++ AP6211_DEBUG("Calling dhdsdio_dpc() from %s\n", __FUNCTION__); ++ resched = dhdsdio_dpc(bus); ++ ++ return resched; ++} ++ ++void ++dhdsdio_isr(void *arg) ++{ ++ dhd_bus_t *bus = (dhd_bus_t*)arg; ++ bcmsdh_info_t *sdh; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (!bus) { ++ AP6211_ERR("%s : bus is null pointer , exit \n", __FUNCTION__); ++ return; ++ } ++ sdh = bus->sdh; ++ ++ if (bus->dhd->busstate == DHD_BUS_DOWN) { ++ AP6211_ERR("%s : bus is down. we have nothing to do\n", __FUNCTION__); ++ return; ++ } ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ /* Count the interrupt call */ ++ bus->intrcount++; ++ bus->ipend = TRUE; ++ ++ /* Shouldn't get this interrupt if we're sleeping? */ ++ if (!SLPAUTO_ENAB(bus)) { ++ if (bus->sleeping) { ++ AP6211_ERR("INTERRUPT WHILE SLEEPING??\n"); ++ return; ++ } else if (!KSO_ENAB(bus)) { ++ AP6211_ERR("ISR in devsleep 1\n"); ++ } ++ } ++ ++ /* Disable additional interrupts (is this needed now)? */ ++ if (bus->intr) { ++ AP6211_DEBUG("%s: disable SDIO interrupts\n", __FUNCTION__); ++ } else { ++ AP6211_ERR("dhdsdio_isr() w/o interrupt configured!\n"); ++ } ++ ++ bcmsdh_intr_disable(sdh); ++ bus->intdis = TRUE; ++ ++#if defined(SDIO_ISR_THREAD) ++ AP6211_DEBUG("Calling dhdsdio_dpc() from %s\n", __FUNCTION__); ++ DHD_OS_WAKE_LOCK(bus->dhd); ++ while (dhdsdio_dpc(bus)); ++ DHD_OS_WAKE_UNLOCK(bus->dhd); ++#else ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++#endif ++ ++} ++ ++#ifdef SDTEST ++static void ++dhdsdio_pktgen_init(dhd_bus_t *bus) ++{ ++ /* Default to specified length, or full range */ ++ if (dhd_pktgen_len) { ++ bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN); ++ bus->pktgen_minlen = bus->pktgen_maxlen; ++ } else { ++ bus->pktgen_maxlen = MAX_PKTGEN_LEN; ++ bus->pktgen_minlen = 0; ++ } ++ bus->pktgen_len = (uint16)bus->pktgen_minlen; ++ ++ /* Default to per-watchdog burst with 10s print time */ ++ bus->pktgen_freq = 1; ++ bus->pktgen_print = dhd_watchdog_ms ? (10000/dhd_watchdog_ms):0; ++ bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000; ++ ++ /* Default to echo mode */ ++ bus->pktgen_mode = DHD_PKTGEN_ECHO; ++ bus->pktgen_stop = 1; ++} ++ ++static void ++dhdsdio_pktgen(dhd_bus_t *bus) ++{ ++ void *pkt; ++ uint8 *data; ++ uint pktcount; ++ uint fillbyte; ++ osl_t *osh = bus->dhd->osh; ++ uint16 len; ++ ulong time_lapse; ++ uint sent_pkts; ++ uint rcvd_pkts; ++ ++ /* Display current count if appropriate */ ++ if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) { ++ bus->pktgen_ptick = 0; ++ AP6211_DEBUG("%s: send attempts %d, rcvd %d, errors %d\n", ++ __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); ++ ++ /* Print throughput stats only for constant length packet runs */ ++ if (bus->pktgen_minlen == bus->pktgen_maxlen) { ++ time_lapse = jiffies - bus->pktgen_prev_time; ++ bus->pktgen_prev_time = jiffies; ++ sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent; ++ bus->pktgen_prev_sent = bus->pktgen_sent; ++ rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd; ++ bus->pktgen_prev_rcvd = bus->pktgen_rcvd; ++ ++ AP6211_DEBUG("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n", ++ __FUNCTION__, ++ (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8, ++ (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8); ++ } ++ } ++ ++ /* For recv mode, just make sure dongle has started sending */ ++ if (bus->pktgen_mode == DHD_PKTGEN_RECV) { ++ if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) { ++ bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING; ++ dhdsdio_sdtest_set(bus, bus->pktgen_total); ++ } ++ return; ++ } ++ ++ /* Otherwise, generate or request the specified number of packets */ ++ for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) { ++ /* Stop if total has been reached */ ++ if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) { ++ bus->pktgen_count = 0; ++ break; ++ } ++ ++ /* Allocate an appropriate-sized packet */ ++ if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { ++ len = SDPCM_TEST_PKT_CNT_FLD_LEN; ++ } else { ++ len = bus->pktgen_len; ++ } ++ if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN), ++ TRUE))) {; ++ AP6211_ERR("%s: PKTGET failed!\n", __FUNCTION__); ++ break; ++ } ++ PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN); ++ data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; ++ ++ /* Write test header cmd and extra based on mode */ ++ switch (bus->pktgen_mode) { ++ case DHD_PKTGEN_ECHO: ++ *data++ = SDPCM_TEST_ECHOREQ; ++ *data++ = (uint8)bus->pktgen_sent; ++ break; ++ ++ case DHD_PKTGEN_SEND: ++ *data++ = SDPCM_TEST_DISCARD; ++ *data++ = (uint8)bus->pktgen_sent; ++ break; ++ ++ case DHD_PKTGEN_RXBURST: ++ *data++ = SDPCM_TEST_BURST; ++ *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */ ++ break; ++ ++ default: ++ AP6211_ERR("Unrecognized pktgen mode %d\n", bus->pktgen_mode); ++ PKTFREE(osh, pkt, TRUE); ++ bus->pktgen_count = 0; ++ return; ++ } ++ ++ /* Write test header length field */ ++ *data++ = (bus->pktgen_len >> 0); ++ *data++ = (bus->pktgen_len >> 8); ++ ++ /* Write frame count in a 4 byte field adjucent to SDPCM test header for ++ * burst mode ++ */ ++ if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { ++ *data++ = (uint8)(bus->pktgen_count >> 0); ++ *data++ = (uint8)(bus->pktgen_count >> 8); ++ *data++ = (uint8)(bus->pktgen_count >> 16); ++ *data++ = (uint8)(bus->pktgen_count >> 24); ++ } else { ++ ++ /* Then fill in the remainder -- N/A for burst */ ++ for (fillbyte = 0; fillbyte < len; fillbyte++) ++ *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent); ++ } ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_DATA_ON()) { ++ data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; ++ prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN); ++ } ++#endif ++ ++ /* Send it */ ++ if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE)) { ++ bus->pktgen_fail++; ++ if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail) ++ bus->pktgen_count = 0; ++ } ++ bus->pktgen_sent++; ++ ++ /* Bump length if not fixed, wrap at max */ ++ if (++bus->pktgen_len > bus->pktgen_maxlen) ++ bus->pktgen_len = (uint16)bus->pktgen_minlen; ++ ++ /* Special case for burst mode: just send one request! */ ++ if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) ++ break; ++ } ++} ++ ++static void ++dhdsdio_sdtest_set(dhd_bus_t *bus, uint count) ++{ ++ void *pkt; ++ uint8 *data; ++ osl_t *osh = bus->dhd->osh; ++ ++ /* Allocate the packet */ ++ if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + ++ SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) { ++ AP6211_ERR("%s: PKTGET failed!\n", __FUNCTION__); ++ return; ++ } ++ PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + ++ SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN); ++ data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; ++ ++ /* Fill in the test header */ ++ *data++ = SDPCM_TEST_SEND; ++ *data++ = (count > 0)?TRUE:FALSE; ++ *data++ = (bus->pktgen_maxlen >> 0); ++ *data++ = (bus->pktgen_maxlen >> 8); ++ *data++ = (uint8)(count >> 0); ++ *data++ = (uint8)(count >> 8); ++ *data++ = (uint8)(count >> 16); ++ *data++ = (uint8)(count >> 24); ++ ++ /* Send it */ ++ if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE)) ++ bus->pktgen_fail++; ++} ++ ++ ++static void ++dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq) ++{ ++ osl_t *osh = bus->dhd->osh; ++ uint8 *data; ++ uint pktlen; ++ ++ uint8 cmd; ++ uint8 extra; ++ uint16 len; ++ uint16 offset; ++ ++ /* Check for min length */ ++ if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) { ++ AP6211_ERR("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen); ++ PKTFREE(osh, pkt, FALSE); ++ return; ++ } ++ ++ /* Extract header fields */ ++ data = PKTDATA(osh, pkt); ++ cmd = *data++; ++ extra = *data++; ++ len = *data++; len += *data++ << 8; ++ AP6211_DEBUG("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len); ++ /* Check length for relevant commands */ ++ if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) { ++ if (pktlen != len + SDPCM_TEST_HDRLEN) { ++ AP6211_ERR("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d" ++ " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len); ++ PKTFREE(osh, pkt, FALSE); ++ return; ++ } ++ } ++ ++ /* Process as per command */ ++ switch (cmd) { ++ case SDPCM_TEST_ECHOREQ: ++ /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */ ++ *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP; ++ if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE) == 0) { ++ bus->pktgen_sent++; ++ } else { ++ bus->pktgen_fail++; ++ PKTFREE(osh, pkt, FALSE); ++ } ++ bus->pktgen_rcvd++; ++ break; ++ ++ case SDPCM_TEST_ECHORSP: ++ if (bus->ext_loop) { ++ PKTFREE(osh, pkt, FALSE); ++ bus->pktgen_rcvd++; ++ break; ++ } ++ ++ for (offset = 0; offset < len; offset++, data++) { ++ if (*data != SDPCM_TEST_FILL(offset, extra)) { ++ AP6211_ERR("dhdsdio_testrcv: echo data mismatch: " ++ "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n", ++ offset, len, SDPCM_TEST_FILL(offset, extra), *data); ++ break; ++ } ++ } ++ PKTFREE(osh, pkt, FALSE); ++ bus->pktgen_rcvd++; ++ break; ++ ++ case SDPCM_TEST_DISCARD: ++ { ++ int i = 0; ++ uint8 *prn = data; ++ uint8 testval = extra; ++ for (i = 0; i < len; i++) { ++ if (*prn != testval) { ++ AP6211_ERR("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n", ++ i, bus->pktgen_rcvd_rcvsession, testval, *prn); ++ prn++; testval++; ++ } ++ } ++ } ++ PKTFREE(osh, pkt, FALSE); ++ bus->pktgen_rcvd++; ++ break; ++ ++ case SDPCM_TEST_BURST: ++ case SDPCM_TEST_SEND: ++ default: ++ AP6211_DEBUG("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d" ++ " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len); ++ PKTFREE(osh, pkt, FALSE); ++ break; ++ } ++ ++ /* For recv mode, stop at limit (and tell dongle to stop sending) */ ++ if (bus->pktgen_mode == DHD_PKTGEN_RECV) { ++ if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) { ++ bus->pktgen_rcvd_rcvsession++; ++ ++ if (bus->pktgen_total && ++ (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) { ++ bus->pktgen_count = 0; ++ AP6211_ERR("Pktgen:rcv test complete!\n"); ++ bus->pktgen_rcv_state = PKTGEN_RCV_IDLE; ++ dhdsdio_sdtest_set(bus, FALSE); ++ bus->pktgen_rcvd_rcvsession = 0; ++ } ++ } ++ } ++} ++#endif /* SDTEST */ ++ ++extern void ++dhd_disable_intr(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus; ++ bus = dhdp->bus; ++ bcmsdh_intr_disable(bus->sdh); ++} ++ ++extern bool ++dhd_bus_watchdog(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ bus = dhdp->bus; ++ ++ if (bus->dhd->dongle_reset) ++ return FALSE; ++ ++ /* Ignore the timer if simulating bus down */ ++ if (!SLPAUTO_ENAB(bus) && bus->sleeping) ++ return FALSE; ++ ++ if (dhdp->busstate == DHD_BUS_DOWN) ++ return FALSE; ++ ++ /* Poll period: check device if appropriate. */ ++ if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) { ++ uint32 intstatus = 0; ++ ++ /* Reset poll tick */ ++ bus->polltick = 0; ++ ++ /* Check device if no interrupts */ ++ if (!bus->intr || (bus->intrcount == bus->lastintrs)) { ++ ++ if (!bus->dpc_sched) { ++ uint8 devpend; ++ devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, ++ SDIOD_CCCR_INTPEND, NULL); ++ intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2); ++ } ++ ++ /* If there is something, make like the ISR and schedule the DPC */ ++ if (intstatus) { ++ bus->pollcnt++; ++ bus->ipend = TRUE; ++ if (bus->intr) { ++ bcmsdh_intr_disable(bus->sdh); ++ } ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ ++ } ++ } ++ ++ /* Update interrupt tracking */ ++ bus->lastintrs = bus->intrcount; ++ } ++ ++#ifdef DHD_DEBUG ++ /* Poll for console output periodically */ ++ if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) { ++ bus->console.count += dhd_watchdog_ms; ++ if (bus->console.count >= dhd_console_ms) { ++ bus->console.count -= dhd_console_ms; ++ /* Make sure backplane clock is on */ ++ if (SLPAUTO_ENAB(bus)) ++ dhdsdio_bussleep(bus, FALSE); ++ else ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ if (dhdsdio_readconsole(bus) < 0) ++ dhd_console_ms = 0; /* On error, stop trying */ ++ } ++ } ++#endif /* DHD_DEBUG */ ++ ++#ifdef SDTEST ++ /* Generate packets if configured */ ++ if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) { ++ /* Make sure backplane clock is on */ ++ if (SLPAUTO_ENAB(bus)) ++ dhdsdio_bussleep(bus, FALSE); ++ else ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ bus->pktgen_tick = 0; ++ dhdsdio_pktgen(bus); ++ } ++#endif ++ ++ /* On idle timeout clear activity flag and/or turn off clock */ ++#ifdef DHD_USE_IDLECOUNT ++ if (bus->activity) ++ bus->activity = FALSE; ++ else { ++ bus->idlecount++; ++ ++ if (bus->idlecount >= bus->idletime) { ++ AP6211_DEBUG("%s: DHD Idle state!!\n", __FUNCTION__); ++ ++ if (SLPAUTO_ENAB(bus)) { ++ if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY) ++ dhd_os_wd_timer(bus->dhd, 0); ++ } else ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ ++ bus->idlecount = 0; ++ } ++ } ++#else ++ if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { ++ if (++bus->idlecount > bus->idletime) { ++ bus->idlecount = 0; ++ if (bus->activity) { ++ bus->activity = FALSE; ++ if (SLPAUTO_ENAB(bus)) { ++ if (!bus->readframes) ++ dhdsdio_bussleep(bus, TRUE); ++ else ++ bus->reqbussleep = TRUE; ++ } ++ else ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ } ++ } ++ } ++#endif /* DHD_USE_IDLECOUNT */ ++ ++ return bus->ipend; ++} ++ ++#ifdef DHD_DEBUG ++extern int ++dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ uint32 addr, val; ++ int rv; ++ void *pkt; ++ ++ /* Address could be zero if CONSOLE := 0 in dongle Makefile */ ++ if (bus->console_addr == 0) ++ return BCME_UNSUPPORTED; ++ ++ /* Exclusive bus access */ ++ dhd_os_sdlock(bus->dhd); ++ ++ /* Don't allow input if dongle is in reset */ ++ if (bus->dhd->dongle_reset) { ++ dhd_os_sdunlock(bus->dhd); ++ return BCME_NOTREADY; ++ } ++ ++ /* Request clock to allow SDIO accesses */ ++ BUS_WAKE(bus); ++ /* No pend allowed since txpkt is called later, ht clk has to be on */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ /* Zero cbuf_index */ ++ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx); ++ val = htol32(0); ++ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) ++ goto done; ++ ++ /* Write message into cbuf */ ++ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf); ++ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0) ++ goto done; ++ ++ /* Write length into vcons_in */ ++ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in); ++ val = htol32(msglen); ++ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) ++ goto done; ++ ++ /* Bump dongle by sending an empty packet on the event channel. ++ * sdpcm_sendup (RX) checks for virtual console input. ++ */ ++ if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL) ++ dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE, FALSE); ++ ++done: ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { ++ bus->activity = FALSE; ++ dhdsdio_clkctl(bus, CLK_NONE, TRUE); ++ } ++ ++ dhd_os_sdunlock(bus->dhd); ++ ++ return rv; ++} ++#endif /* DHD_DEBUG */ ++ ++#ifdef DHD_DEBUG ++static void ++dhd_dump_cis(uint fn, uint8 *cis) ++{ ++ uint byte, tag, tdata; ++ AP6211_DEBUG("Function %d CIS:\n", fn); ++ ++ for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) { ++ if ((byte % 16) == 0) ++ AP6211_DUMP(" "); ++ AP6211_DUMP("%02x ", cis[byte]); ++ if ((byte % 16) == 15) ++ AP6211_DUMP("\n"); ++ if (!tdata--) { ++ tag = cis[byte]; ++ if (tag == 0xff) ++ break; ++ else if (!tag) ++ tdata = 0; ++ else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT) ++ tdata = cis[byte + 1] + 1; ++ else ++ AP6211_DUMP("]"); ++ } ++ } ++ if ((byte % 16) != 15) ++ AP6211_DUMP("\n"); ++} ++#endif /* DHD_DEBUG */ ++ ++static bool ++dhdsdio_chipmatch(uint16 chipid) ++{ ++ if (chipid == BCM4325_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4329_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4315_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4319_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4336_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4330_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43237_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43362_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4314_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4334_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43341_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43239_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4324_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4335_CHIP_ID) ++ return TRUE; ++ return FALSE; ++} ++ ++static void * ++dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, ++ uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh) ++{ ++ int ret; ++ dhd_bus_t *bus; ++#ifdef GET_CUSTOM_MAC_ENABLE ++ struct ether_addr ea_addr; ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ ++ if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { ++ AP6211_DEBUG("%s : no mutex held. set lock\n", __FUNCTION__); ++ } ++ else { ++ AP6211_DEBUG("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__); ++ } ++ mutex_lock(&_dhd_sdio_mutex_lock_); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ ++ ++ /* Init global variables at run-time, not as part of the declaration. ++ * This is required to support init/de-init of the driver. Initialization ++ * of globals as part of the declaration results in non-deterministic ++ * behavior since the value of the globals may be different on the ++ * first time that the driver is initialized vs subsequent initializations. ++ */ ++ dhd_txbound = DHD_TXBOUND; ++ dhd_rxbound = DHD_RXBOUND; ++ dhd_alignctl = TRUE; ++ sd1idle = TRUE; ++ dhd_readahead = TRUE; ++ retrydata = FALSE; ++ dhd_doflow = FALSE; ++ dhd_dongle_memsize = 0; ++ dhd_txminmax = DHD_TXMINMAX; ++ ++ forcealign = TRUE; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ AP6211_DEBUG("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid); ++ ++ /* We make assumptions about address window mappings */ ++ ASSERT((uintptr)regsva == SI_ENUM_BASE); ++ ++ /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start ++ * means early parse could fail, so here we should get either an ID ++ * we recognize OR (-1) indicating we must request power first. ++ */ ++ /* Check the Vendor ID */ ++ switch (venid) { ++ case 0x0000: ++ case VENDOR_BROADCOM: ++ break; ++ default: ++ AP6211_ERR("%s: unknown vendor: 0x%04x\n", ++ __FUNCTION__, venid); ++ goto forcereturn; ++ } ++ ++ /* Check the Device ID and make sure it's one that we support */ ++ switch (devid) { ++ case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */ ++ case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */ ++ case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */ ++ AP6211_DEBUG("%s: found 4325 Dongle\n", __FUNCTION__); ++ break; ++ case BCM4329_D11N_ID: /* 4329 802.11n dualband device */ ++ case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */ ++ case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */ ++ case 0x4329: ++ AP6211_DEBUG("%s: found 4329 Dongle\n", __FUNCTION__); ++ break; ++ case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */ ++ case BCM4315_D11G_ID: /* 4315 802.11g id */ ++ case BCM4315_D11A_ID: /* 4315 802.11a id */ ++ AP6211_DEBUG("%s: found 4315 Dongle\n", __FUNCTION__); ++ break; ++ case BCM4319_D11N_ID: /* 4319 802.11n id */ ++ case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */ ++ case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */ ++ AP6211_DEBUG("%s: found 4319 Dongle\n", __FUNCTION__); ++ break; ++ case 0: ++ AP6211_DEBUG("%s: allow device id 0, will check chip internals\n", ++ __FUNCTION__); ++ break; ++ ++ default: ++ AP6211_ERR("%s: skipping 0x%04x/0x%04x, not a dongle\n", ++ __FUNCTION__, venid, devid); ++ goto forcereturn; ++ } ++ ++ if (osh == NULL) { ++ /* Ask the OS interface part for an OSL handle */ ++ if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) { ++ AP6211_ERR("%s: osl_attach failed!\n", __FUNCTION__); ++ goto forcereturn; ++ } ++ } ++ ++ /* Allocate private bus interface state */ ++ if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) { ++ AP6211_ERR("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__); ++ goto fail; ++ } ++ bzero(bus, sizeof(dhd_bus_t)); ++ bus->sdh = sdh; ++ bus->cl_devid = (uint16)devid; ++ bus->bus = DHD_BUS; ++ bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; ++ bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */ ++ ++ /* attach the common module */ ++ dhd_common_init(osh); ++ ++ /* attempt to attach to the dongle */ ++ if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) { ++ AP6211_ERR("%s: dhdsdio_probe_attach failed\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ /* Attach to the dhd/OS/network interface */ ++ if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) { ++ AP6211_ERR("%s: dhd_attach failed\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ /* Allocate buffers */ ++ if (!(dhdsdio_probe_malloc(bus, osh, sdh))) { ++ AP6211_ERR("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ if (!(dhdsdio_probe_init(bus, osh, sdh))) { ++ AP6211_ERR("%s: dhdsdio_probe_init failed\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ if (bus->intr) { ++ /* Register interrupt callback, but mask it (not operational yet). */ ++ AP6211_DEBUG("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__); ++ bcmsdh_intr_disable(sdh); ++ if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) { ++ AP6211_ERR("%s: FAILED: bcmsdh_intr_reg returned %d\n", ++ __FUNCTION__, ret); ++ goto fail; ++ } ++ AP6211_DEBUG("%s: registered SDIO interrupt function ok\n", __FUNCTION__); ++ } else { ++ AP6211_DEBUG("%s: SDIO interrupt function is NOT registered due to polling mode\n", ++ __FUNCTION__); ++ } ++ ++ AP6211_DEBUG("%s: completed!!\n", __FUNCTION__); ++ ++#ifdef GET_CUSTOM_MAC_ENABLE ++ /* Read MAC address from external customer place */ ++ memset(&ea_addr, 0, sizeof(ea_addr)); ++ ret = dhd_custom_get_mac_address(ea_addr.octet); ++ if (!ret) { ++ memcpy(bus->dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN); ++ } ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++ ++ /* if firmware path present try to download and bring up bus */ ++ if (dhd_download_fw_on_driverload) { ++ if ((ret = dhd_bus_start(bus->dhd)) != 0) { ++ AP6211_ERR("%s: dhd_bus_start failed\n", __FUNCTION__); ++ goto fail; ++ } ++ } ++ /* Ok, have the per-port tell the stack we're open for business */ ++ if (dhd_net_attach(bus->dhd, 0) != 0) { ++ AP6211_ERR("%s: Net attach failed!!\n", __FUNCTION__); ++ goto fail; ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ mutex_unlock(&_dhd_sdio_mutex_lock_); ++ AP6211_DEBUG("%s : the lock is released.\n", __FUNCTION__); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++ ++ return bus; ++ ++fail: ++ dhdsdio_release(bus, osh); ++ ++forcereturn: ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ mutex_unlock(&_dhd_sdio_mutex_lock_); ++ AP6211_DEBUG("%s : the lock is released.\n", __FUNCTION__); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++ ++ return NULL; ++} ++ ++static bool ++dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, ++ uint16 devid) ++{ ++ int err = 0; ++ uint8 clkctl = 0; ++ ++ bus->alp_only = TRUE; ++ bus->sih = NULL; ++ ++ /* Return the window to backplane enumeration space for core access */ ++ if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) { ++ AP6211_ERR("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__); ++ } ++ ++#ifdef DHD_DEBUG ++ AP6211_DEBUG("F1 signature read @0x18000000=0x%4x\n", ++ bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4)); ++ ++#endif /* DHD_DEBUG */ ++ ++ ++ /* Force PLL off until si_attach() programs PLL control regs */ ++ ++ ++ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err); ++ if (!err) ++ clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ ++ if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) { ++ AP6211_ERR("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n", ++ err, DHD_INIT_CLKCTL1, clkctl); ++ goto fail; ++ } ++ ++#ifdef DHD_DEBUG ++ if (DHD_INFO_ON()) { ++ uint fn, numfn; ++ uint8 *cis[SDIOD_MAX_IOFUNCS]; ++ int err = 0; ++ ++ numfn = bcmsdh_query_iofnum(sdh); ++ ASSERT(numfn <= SDIOD_MAX_IOFUNCS); ++ ++ /* Make sure ALP is available before trying to read CIS */ ++ SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, NULL)), ++ !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY); ++ ++ /* Now request ALP be put on the bus */ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ DHD_INIT_CLKCTL2, &err); ++ OSL_DELAY(65); ++ ++ for (fn = 0; fn <= numfn; fn++) { ++ if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) { ++ AP6211_DEBUG("dhdsdio_probe: fn %d cis malloc failed\n", fn); ++ break; ++ } ++ bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT); ++ ++ if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) { ++ AP6211_DEBUG("dhdsdio_probe: fn %d cis read err %d\n", fn, err); ++ MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); ++ break; ++ } ++ dhd_dump_cis(fn, cis[fn]); ++ } ++ ++ while (fn-- > 0) { ++ ASSERT(cis[fn]); ++ MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); ++ } ++ ++ if (err) { ++ AP6211_ERR("dhdsdio_probe: failure reading or parsing CIS\n"); ++ goto fail; ++ } ++ } ++#endif /* DHD_DEBUG */ ++ ++ /* si_attach() will provide an SI handle and scan the backplane */ ++ if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh, ++ &bus->vars, &bus->varsz))) { ++ AP6211_ERR("%s: si_attach failed!\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev); ++ ++ if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) { ++ AP6211_ERR("%s: unsupported chip: 0x%04x\n", ++ __FUNCTION__, bus->sih->chip); ++ goto fail; ++ } ++ ++ if (bus->sih->buscorerev >= 12) ++ dhdsdio_clk_kso_init(bus); ++ else ++ bus->kso = TRUE; ++ ++ if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) { ++ } ++ ++ si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength); ++ ++ ++ /* Get info on the ARM and SOCRAM cores... */ ++ if (!DHD_NOPMU(bus)) { ++ if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) || ++ (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) || ++ (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { ++ bus->armrev = si_corerev(bus->sih); ++ } else { ++ AP6211_ERR("%s: failed to find ARM core!\n", __FUNCTION__); ++ goto fail; ++ } ++ ++ if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { ++ if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { ++ AP6211_ERR("%s: failed to find SOCRAM memory!\n", __FUNCTION__); ++ goto fail; ++ } ++ } else { ++ /* cr4 has a different way to find the RAM size from TCM's */ ++ if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) { ++ AP6211_ERR("%s: failed to find CR4-TCM memory!\n", __FUNCTION__); ++ goto fail; ++ } ++ /* also populate base address */ ++ bus->dongle_ram_base = CR4_RAM_BASE; ++ } ++ bus->ramsize = bus->orig_ramsize; ++ if (dhd_dongle_memsize) ++ dhd_dongle_setmemsize(bus, dhd_dongle_memsize); ++ ++ AP6211_DEBUG("DHD: dongle ram size is set to %d(orig %d)\n", ++ bus->ramsize, bus->orig_ramsize); ++ ++ bus->srmemsize = si_socram_srmem_size(bus->sih); ++ } ++ ++ /* ...but normally deal with the SDPCMDEV core */ ++ if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) && ++ !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) { ++ AP6211_ERR("%s: failed to find SDIODEV core!\n", __FUNCTION__); ++ goto fail; ++ } ++ bus->sdpcmrev = si_corerev(bus->sih); ++ ++ /* Set core control so an SDIO reset does a backplane reset */ ++ OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN); ++ bus->rxint_mode = SDIO_DEVICE_HMB_RXINT; ++ ++ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && ++ (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) ++ { ++ uint32 val; ++ ++ val = R_REG(osh, &bus->regs->corecontrol); ++ val &= ~CC_XMTDATAAVAIL_MODE; ++ val |= CC_XMTDATAAVAIL_CTRL; ++ W_REG(osh, &bus->regs->corecontrol, val); ++ } ++ ++ ++ pktq_init(&bus->txq, (PRIOMASK + 1), QLEN); ++ ++ /* Locate an appropriately-aligned portion of hdrbuf */ ++ bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN); ++ ++ /* Set the poll and/or interrupt flags */ ++ bus->intr = (bool)dhd_intr; ++ if ((bus->poll = (bool)dhd_poll)) ++ bus->pollrate = 1; ++ ++#ifdef BCMSDIOH_TXGLOM ++ /* Setting default Glom mode */ ++ bus->glom_mode = SDPCM_TXGLOM_CPY; ++ /* Setting default Glom size */ ++ bus->glomsize = SDPCM_DEFGLOM_SIZE; ++#endif ++ ++ return TRUE; ++ ++fail: ++ if (bus->sih != NULL) { ++ si_detach(bus->sih); ++ bus->sih = NULL; ++ } ++ return FALSE; ++} ++ ++static bool ++dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh) ++{ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (bus->dhd->maxctl) { ++ bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN; ++ if (!(bus->rxbuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_RXBUF, bus->rxblen))) { ++ AP6211_ERR("%s: MALLOC of %d-byte rxbuf failed\n", ++ __FUNCTION__, bus->rxblen); ++ goto fail; ++ } ++ } ++ /* Allocate buffer to receive glomed packet */ ++ if (!(bus->databuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) { ++ AP6211_ERR("%s: MALLOC of %d-byte databuf failed\n", ++ __FUNCTION__, MAX_DATA_BUF); ++ /* release rxbuf which was already located as above */ ++ if (!bus->rxblen) ++ DHD_OS_PREFREE(osh, bus->rxbuf, bus->rxblen); ++ goto fail; ++ } ++ ++ /* Align the buffer */ ++ if ((uintptr)bus->databuf % DHD_SDALIGN) ++ bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN)); ++ else ++ bus->dataptr = bus->databuf; ++ ++ return TRUE; ++ ++fail: ++ return FALSE; ++} ++ ++static bool ++dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh) ++{ ++ int32 fnum; ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++#ifdef SDTEST ++ dhdsdio_pktgen_init(bus); ++#endif /* SDTEST */ ++ ++ /* Disable F2 to clear any intermediate frame state on the dongle */ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); ++ ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ bus->sleeping = FALSE; ++ bus->rxflow = FALSE; ++ bus->prev_rxlim_hit = 0; ++ ++ /* Done with backplane-dependent accesses, can drop clock... */ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); ++ ++ /* ...and initialize clock/power states */ ++ bus->clkstate = CLK_SDONLY; ++ bus->idletime = (int32)dhd_idletime; ++ bus->idleclock = DHD_IDLE_ACTIVE; ++ ++ /* Query the SD clock speed */ ++ if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0, ++ &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { ++ AP6211_ERR("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"); ++ bus->sd_divisor = -1; ++ } else { ++ AP6211_DEBUG("%s: Initial value for %s is %d\n", ++ __FUNCTION__, "sd_divisor", bus->sd_divisor); ++ } ++ ++ /* Query the SD bus mode */ ++ if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0, ++ &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { ++ AP6211_ERR("%s: fail on %s get\n", __FUNCTION__, "sd_mode"); ++ bus->sd_mode = -1; ++ } else { ++ AP6211_DEBUG("%s: Initial value for %s is %d\n", ++ __FUNCTION__, "sd_mode", bus->sd_mode); ++ } ++ ++ /* Query the F2 block size, set roundup accordingly */ ++ fnum = 2; ++ if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32), ++ &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { ++ bus->blocksize = 0; ++ AP6211_ERR("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"); ++ } else { ++ AP6211_DEBUG("%s: Initial value for %s is %d\n", ++ __FUNCTION__, "sd_blocksize", bus->blocksize); ++ } ++ bus->roundup = MIN(max_roundup, bus->blocksize); ++ ++ /* Query if bus module supports packet chaining, default to use if supported */ ++ if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0, ++ &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) { ++ bus->sd_rxchain = FALSE; ++ } else { ++ AP6211_DEBUG("%s: bus module (through bcmsdh API) %s chaining\n", ++ __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")); ++ } ++ bus->use_rxchain = (bool)bus->sd_rxchain; ++ ++ return TRUE; ++} ++ ++void ++dhd_bus_select_firmware_name_by_chip(struct dhd_bus *bus, char *dst, char *src) ++{ ++ int fw_type, ag_type; ++ static uint chip, chiprev, first=1; ++ int i; ++ ++ if (first) { ++ chip = bus->sih->chip; ++ chiprev = bus->sih->chiprev; ++ first = 0; ++ } ++ if (src[0] == '\0') { ++#ifdef CONFIG_AP6211_FW_PATH ++ bcm_strncpy_s(src, sizeof(fw_path), CONFIG_AP6211_FW_PATH, MOD_PARAM_PATHLEN-1); ++ if (src[0] == '\0') ++#endif ++ { ++ AP6211_DEBUG("src firmware path is null\n"); ++ return; ++ } ++ } ++ ++ strcpy(dst, src); ++#ifndef FW_PATH_AUTO_SELECT ++ return; ++#endif ++ ++ /* find out the last '/' */ ++ i = strlen(dst); ++ while (i>0){ ++ if (dst[i] == '/') break; ++ i--; ++ } ++#ifdef BAND_AG ++ ag_type = FW_TYPE_AG; ++#else ++ ag_type = strstr(&dst[i], "_ag") ? FW_TYPE_AG : FW_TYPE_G; ++#endif ++ fw_type = (strstr(&dst[i], "_mfg") ? ++ FW_TYPE_MFG : (strstr(&dst[i], "_apsta") ? ++ FW_TYPE_APSTA : (strstr(&dst[i], "_p2p") ? ++ FW_TYPE_P2P : FW_TYPE_STA))); ++ ++ ++ switch (chip) { ++ case BCM4330_CHIP_ID: ++ if (ag_type == FW_TYPE_G) { ++ if (chiprev == BCM4330B2_CHIP_REV) ++ strcpy(&dst[i+1], bcm40183b2_fw_name[fw_type]); ++ break; ++ } else { ++ if (chiprev == BCM4330B2_CHIP_REV) ++ strcpy(&dst[i+1], bcm40183b2ag_fw_name[fw_type]); ++ break; ++ } ++ case BCM43362_CHIP_ID: ++ if (chiprev == BCM43362A0_CHIP_REV) ++ strcpy(&dst[i+1], bcm40181a0_fw_name[fw_type]); ++ else ++ strcpy(&dst[i+1], bcm40181a2_fw_name[fw_type]); ++ break; ++ case BCM43341_CHIP_ID: ++ if (chiprev == BCM43341B0_CHIP_REV) ++ strcpy(&dst[i+1], bcm43341b0ag_fw_name[fw_type]); ++ break; ++ case BCM4324_CHIP_ID: ++ if (chiprev == BCM43241B4_CHIP_REV) ++ strcpy(&dst[i+1], bcm43241b4ag_fw_name[fw_type]); ++ break; ++ } ++ ++ AP6211_DEBUG("%s: firmware_path=%s\n", __FUNCTION__, dst); ++} ++ ++bool ++dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, ++ char *pfw_path, char *pnv_path) ++{ ++ bool ret; ++ bus->fw_path = pfw_path; ++ bus->nv_path = pnv_path; ++ ++ ret = dhdsdio_download_firmware(bus, osh, bus->sdh); ++ ++ ++ return ret; ++} ++ ++static bool ++dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh) ++{ ++ bool ret; ++ ++ DHD_OS_WAKE_LOCK(bus->dhd); ++ ++ /* Download the firmware */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ AP6211_ERR("Final fw_path=%s\n", bus->fw_path); ++ AP6211_ERR("Final nv_path=%s\n", bus->nv_path); ++ ret = _dhdsdio_download_firmware(bus) == 0; ++ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ ++ DHD_OS_WAKE_UNLOCK(bus->dhd); ++ return ret; ++} ++ ++/* Detach and free everything */ ++static void ++dhdsdio_release(dhd_bus_t *bus, osl_t *osh) ++{ ++ bool dongle_isolation = FALSE; ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (bus) { ++ ASSERT(osh); ++ ++ if (bus->dhd) { ++ dongle_isolation = bus->dhd->dongle_isolation; ++ dhd_detach(bus->dhd); ++ } ++ ++ /* De-register interrupt handler */ ++ bcmsdh_intr_disable(bus->sdh); ++ bcmsdh_intr_dereg(bus->sdh); ++ ++ if (bus->dhd) { ++ dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE); ++ dhd_free(bus->dhd); ++ bus->dhd = NULL; ++ } ++ ++ dhdsdio_release_malloc(bus, osh); ++ ++#ifdef DHD_DEBUG ++ if (bus->console.buf != NULL) ++ MFREE(osh, bus->console.buf, bus->console.bufsize); ++#endif ++ ++ MFREE(osh, bus, sizeof(dhd_bus_t)); ++ } ++ ++ if (osh) ++ dhd_osl_detach(osh); ++ ++ AP6211_DEBUG("%s: Disconnected\n", __FUNCTION__); ++} ++ ++static void ++dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) ++{ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (bus->dhd && bus->dhd->dongle_reset) ++ return; ++ ++ if (bus->rxbuf) { ++#ifndef CONFIG_DHD_USE_STATIC_BUF ++ MFREE(osh, bus->rxbuf, bus->rxblen); ++#endif ++ bus->rxctl = bus->rxbuf = NULL; ++ bus->rxlen = 0; ++ } ++ ++ if (bus->databuf) { ++#ifndef CONFIG_DHD_USE_STATIC_BUF ++ MFREE(osh, bus->databuf, MAX_DATA_BUF); ++#endif ++ bus->databuf = NULL; ++ } ++ ++ if (bus->vars && bus->varsz) { ++ MFREE(osh, bus->vars, bus->varsz); ++ bus->vars = NULL; ++ } ++ ++} ++ ++ ++static void ++dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag) ++{ ++ AP6211_DEBUG("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__, ++ bus->dhd, bus->dhd->dongle_reset); ++ ++ if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag) ++ return; ++ ++ if (bus->sih) { ++#if !defined(BCMLXSDMMC) ++ if (bus->dhd) { ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ } ++ if (KSO_ENAB(bus) && (dongle_isolation == FALSE)) ++ si_watchdog(bus->sih, 4); ++#endif /* !defined(BCMLXSDMMC) */ ++ if (bus->dhd) { ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ } ++ si_detach(bus->sih); ++ bus->sih = NULL; ++ if (bus->vars && bus->varsz) ++ MFREE(osh, bus->vars, bus->varsz); ++ bus->vars = NULL; ++ } ++ ++ AP6211_DEBUG("%s: Disconnected\n", __FUNCTION__); ++} ++ ++static void ++dhdsdio_disconnect(void *ptr) ++{ ++ dhd_bus_t *bus = (dhd_bus_t *)ptr; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ ++ if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { ++ AP6211_DEBUG("%s : no mutex held. set lock\n", __FUNCTION__); ++ } ++ else { ++ AP6211_DEBUG("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__); ++ } ++ mutex_lock(&_dhd_sdio_mutex_lock_); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ ++ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ if (bus) { ++ ASSERT(bus->dhd); ++ dhdsdio_release(bus, bus->dhd->osh); ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ mutex_unlock(&_dhd_sdio_mutex_lock_); ++ AP6211_ERR("%s : the lock is released.\n", __FUNCTION__); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ ++ ++ AP6211_DEBUG("%s: Disconnected\n", __FUNCTION__); ++} ++ ++ ++/* Register/Unregister functions are called by the main DHD entry ++ * point (e.g. module insertion) to link with the bus driver, in ++ * order to look for or await the device. ++ */ ++ ++static bcmsdh_driver_t dhd_sdio = { ++ dhdsdio_probe, ++ dhdsdio_disconnect ++}; ++ ++int ++dhd_bus_register(void) ++{ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ return bcmsdh_register(&dhd_sdio); ++} ++ ++void ++dhd_bus_unregister(void) ++{ ++ AP6211_DEBUG("%s: Enter\n", __FUNCTION__); ++ ++ bcmsdh_unregister(); ++} ++ ++#if defined(BCMLXSDMMC) ++/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ ++int dhd_bus_reg_sdio_notify(void* semaphore) ++{ ++ return bcmsdh_reg_sdio_notify(semaphore); ++} ++ ++void dhd_bus_unreg_sdio_notify(void) ++{ ++ bcmsdh_unreg_sdio_notify(); ++} ++#endif /* defined(BCMLXSDMMC) */ ++ ++#ifdef BCMEMBEDIMAGE ++static int ++dhdsdio_download_code_array(struct dhd_bus *bus) ++{ ++ int bcmerror = -1; ++ int offset = 0; ++ unsigned char *ularray = NULL; ++ ++ AP6211_ERR("%s: download embedded firmware...\n", __FUNCTION__); ++ ++ /* Download image */ ++ while ((offset + MEMBLOCK) < sizeof(dlarray)) { ++ bcmerror = dhdsdio_membytes(bus, TRUE, offset, ++ (uint8 *) (dlarray + offset), MEMBLOCK); ++ if (bcmerror) { ++ AP6211_ERR("%s: error %d on writing %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, MEMBLOCK, offset); ++ goto err; ++ } ++ ++ offset += MEMBLOCK; ++ } ++ ++ if (offset < sizeof(dlarray)) { ++ bcmerror = dhdsdio_membytes(bus, TRUE, offset, ++ (uint8 *) (dlarray + offset), sizeof(dlarray) - offset); ++ if (bcmerror) { ++ AP6211_ERR("%s: error %d on writing %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset); ++ goto err; ++ } ++ } ++ ++#ifdef DHD_DEBUG ++ /* Upload and compare the downloaded code */ ++ { ++ ularray = MALLOC(bus->dhd->osh, bus->ramsize); ++ /* Upload image to verify downloaded contents. */ ++ offset = 0; ++ memset(ularray, 0xaa, bus->ramsize); ++ while ((offset + MEMBLOCK) < sizeof(dlarray)) { ++ bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK); ++ if (bcmerror) { ++ AP6211_ERR("%s: error %d on reading %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, MEMBLOCK, offset); ++ goto err; ++ } ++ ++ offset += MEMBLOCK; ++ } ++ ++ if (offset < sizeof(dlarray)) { ++ bcmerror = dhdsdio_membytes(bus, FALSE, offset, ++ ularray + offset, sizeof(dlarray) - offset); ++ if (bcmerror) { ++ AP6211_ERR("%s: error %d on reading %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset); ++ goto err; ++ } ++ } ++ ++ if (memcmp(dlarray, ularray, sizeof(dlarray))) { ++ AP6211_ERR("%s: Downloaded image is corrupted (%s, %s, %s).\n", ++ __FUNCTION__, dlimagename, dlimagever, dlimagedate); ++ goto err; ++ } else ++ AP6211_ERR("%s: Download, Upload and compare succeeded (%s, %s, %s).\n", ++ __FUNCTION__, dlimagename, dlimagever, dlimagedate); ++ ++ } ++#endif /* DHD_DEBUG */ ++ ++err: ++ if (ularray) ++ MFREE(bus->dhd->osh, ularray, bus->ramsize); ++ return bcmerror; ++} ++#endif /* BCMEMBEDIMAGE */ ++ ++static int ++dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) ++{ ++ int bcmerror = -1; ++ int offset = 0; ++ int len; ++ void *image = NULL; ++ uint8 *memblock = NULL, *memptr; ++ uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct ++ ++ AP6211_ERR("download firmware %s\n", pfw_path); ++ ++ image = dhd_os_open_image(pfw_path); ++ if (image == NULL) ++ goto err; ++ ++ memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); ++ if (memblock == NULL) { ++ AP6211_ERR("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK); ++ goto err; ++ } ++ if (dhd_msg_level & DHD_TRACE_VAL) { ++ memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); ++ if (memptr_tmp == NULL) { ++ AP6211_ERR("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK); ++ goto err; ++ } ++ } ++ if ((uint32)(uintptr)memblock % DHD_SDALIGN) ++ memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); ++ ++ /* Download image */ ++ while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) { ++ if (len < 0) { ++ AP6211_ERR("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len); ++ bcmerror = BCME_ERROR; ++ goto err; ++ } ++ bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len); ++ if (bcmerror) { ++ AP6211_ERR("%s: error %d on writing %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, MEMBLOCK, offset); ++ goto err; ++ } ++ ++ if (dhd_msg_level & DHD_TRACE_VAL) { ++ bcmerror = dhdsdio_membytes(bus, FALSE, offset, memptr_tmp, len); ++ if (bcmerror) { ++ AP6211_ERR("%s: error %d on reading %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, MEMBLOCK, offset); ++ goto err; ++ } ++ if (memcmp(memptr_tmp, memptr, len)) { ++ AP6211_ERR("%s: Downloaded image is corrupted.\n", __FUNCTION__); ++ goto err; ++ } else ++ AP6211_ERR("%s: Download, Upload and compare succeeded.\n", __FUNCTION__); ++ } ++ offset += MEMBLOCK; ++ } ++ ++err: ++ if (memblock) ++ MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN); ++ if (dhd_msg_level & DHD_TRACE_VAL) { ++ if (memptr_tmp) ++ MFREE(bus->dhd->osh, memptr_tmp, MEMBLOCK + DHD_SDALIGN); ++ } ++ ++ if (image) ++ dhd_os_close_image(image); ++ ++ return bcmerror; ++} ++ ++/* ++ EXAMPLE: nvram_array ++ nvram_arry format: ++ name=value ++ Use carriage return at the end of each assignment, and an empty string with ++ carriage return at the end of array. ++ ++ For example: ++ unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"}; ++ Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx. ++ ++ Search "EXAMPLE: nvram_array" to see how the array is activated. ++*/ ++ ++void ++dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params) ++{ ++ bus->nvram_params = nvram_params; ++} ++ ++static int ++dhdsdio_download_nvram(struct dhd_bus *bus) ++{ ++ int bcmerror = -1; ++ uint len; ++ void * image = NULL; ++ char * memblock = NULL; ++ char *bufp; ++ char *pnv_path; ++ bool nvram_file_exists; ++ ++ pnv_path = bus->nv_path; ++ ++ nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); ++ if (!nvram_file_exists && (bus->nvram_params == NULL)) ++ return (0); ++ ++ if (nvram_file_exists) { ++ image = dhd_os_open_image(pnv_path); ++ if (image == NULL) ++ goto err; ++ } ++ ++ memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE); ++ if (memblock == NULL) { ++ AP6211_ERR("%s: Failed to allocate memory %d bytes\n", ++ __FUNCTION__, MAX_NVRAMBUF_SIZE); ++ goto err; ++ } ++ ++ /* Download variables */ ++ if (nvram_file_exists) { ++ len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image); ++ } ++ else { ++ len = strlen(bus->nvram_params); ++ ASSERT(len <= MAX_NVRAMBUF_SIZE); ++ memcpy(memblock, bus->nvram_params, len); ++ } ++ if (len > 0 && len < MAX_NVRAMBUF_SIZE) { ++ bufp = (char *)memblock; ++ bufp[len] = 0; ++ len = process_nvram_vars(bufp, len); ++ if (len % 4) { ++ len += 4 - (len % 4); ++ } ++ bufp += len; ++ *bufp++ = 0; ++ if (len) ++ bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1); ++ if (bcmerror) { ++ AP6211_ERR("%s: error downloading vars: %d\n", ++ __FUNCTION__, bcmerror); ++ } ++ } ++ else { ++ AP6211_ERR("%s: error reading nvram file: %d\n", ++ __FUNCTION__, len); ++ bcmerror = BCME_SDIO_ERROR; ++ } ++ ++err: ++ if (memblock) ++ MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); ++ ++ if (image) ++ dhd_os_close_image(image); ++ ++ return bcmerror; ++} ++ ++static int ++_dhdsdio_download_firmware(struct dhd_bus *bus) ++{ ++ int bcmerror = -1; ++ ++ bool embed = FALSE; /* download embedded firmware */ ++ bool dlok = FALSE; /* download firmware succeeded */ ++ ++ /* Out immediately if no image to download */ ++ if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) { ++#ifdef BCMEMBEDIMAGE ++ embed = TRUE; ++#else ++ return 0; ++#endif ++ } ++ ++ /* Keep arm in reset */ ++ if (dhdsdio_download_state(bus, TRUE)) { ++ AP6211_ERR("%s: error placing ARM core in reset\n", __FUNCTION__); ++ goto err; ++ } ++ ++ /* External image takes precedence if specified */ ++ if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) { ++ if (dhdsdio_download_code_file(bus, bus->fw_path)) { ++ AP6211_ERR("%s: dongle image file download failed\n", __FUNCTION__); ++#ifdef BCMEMBEDIMAGE ++ embed = TRUE; ++#else ++ goto err; ++#endif ++ } ++ else { ++ embed = FALSE; ++ dlok = TRUE; ++ } ++ } ++#ifdef BCMEMBEDIMAGE ++ if (embed) { ++ if (dhdsdio_download_code_array(bus)) { ++ AP6211_ERR("%s: dongle image array download failed\n", __FUNCTION__); ++ goto err; ++ } ++ else { ++ dlok = TRUE; ++ } ++ } ++#else ++ BCM_REFERENCE(embed); ++#endif ++ if (!dlok) { ++ AP6211_ERR("%s: dongle image download failed\n", __FUNCTION__); ++ goto err; ++ } ++ ++ /* EXAMPLE: nvram_array */ ++ /* If a valid nvram_arry is specified as above, it can be passed down to dongle */ ++ /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */ ++ ++ /* External nvram takes precedence if specified */ ++ if (dhdsdio_download_nvram(bus)) { ++ AP6211_ERR("%s: dongle nvram file download failed\n", __FUNCTION__); ++ goto err; ++ } ++ ++ /* Take arm out of reset */ ++ if (dhdsdio_download_state(bus, FALSE)) { ++ AP6211_ERR("%s: error getting out of ARM core reset\n", __FUNCTION__); ++ goto err; ++ } ++ ++ bcmerror = 0; ++ ++err: ++ return bcmerror; ++} ++ ++static int ++dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, ++ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle) ++{ ++ int status; ++ ++ if (!KSO_ENAB(bus)) { ++ AP6211_ERR("%s: Device asleep\n", __FUNCTION__); ++ return BCME_NODEVICE; ++ } ++ ++ status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle); ++ ++ return status; ++} ++ ++static int ++dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, ++ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle) ++{ ++ if (!KSO_ENAB(bus)) { ++ AP6211_ERR("%s: Device asleep\n", __FUNCTION__); ++ return BCME_NODEVICE; ++ } ++ ++ return (bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle)); ++} ++ ++#ifdef BCMSDIOH_TXGLOM ++static void ++dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, uint len) ++{ ++ bcmsdh_glom_post(bus->sdh, frame, len); ++} ++ ++static void ++dhd_bcmsdh_glom_clear(dhd_bus_t *bus) ++{ ++ bcmsdh_glom_clear(bus->sdh); ++} ++#endif ++ ++uint ++dhd_bus_chip(struct dhd_bus *bus) ++{ ++ ASSERT(bus->sih != NULL); ++ return bus->sih->chip; ++} ++ ++void * ++dhd_bus_pub(struct dhd_bus *bus) ++{ ++ return bus->dhd; ++} ++ ++void * ++dhd_bus_txq(struct dhd_bus *bus) ++{ ++ return &bus->txq; ++} ++ ++uint ++dhd_bus_hdrlen(struct dhd_bus *bus) ++{ ++ return SDPCM_HDRLEN; ++} ++ ++int ++dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) ++{ ++ int bcmerror = 0; ++ dhd_bus_t *bus; ++ ++ bus = dhdp->bus; ++ ++ if (flag == TRUE) { ++ if (!bus->dhd->dongle_reset) { ++ dhd_os_sdlock(dhdp); ++ dhd_os_wd_timer(dhdp, 0); ++#if !defined(IGNORE_ETH0_DOWN) ++ /* Force flow control as protection when stop come before ifconfig_down */ ++ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); ++#endif /* !defined(IGNORE_ETH0_DOWN) */ ++ /* Expect app to have torn down any connection before calling */ ++ /* Stop the bus, disable F2 */ ++ dhd_bus_stop(bus, FALSE); ++ ++#if defined(OOB_INTR_ONLY) ++ /* Clean up any pending IRQ */ ++ bcmsdh_set_irq(FALSE); ++#endif ++ ++ /* Clean tx/rx buffer pointers, detach from the dongle */ ++ dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE); ++ ++ bus->dhd->dongle_reset = TRUE; ++ bus->dhd->up = FALSE; ++#ifdef BCMSDIOH_TXGLOM ++ dhd_txglom_enable(dhdp, FALSE); ++#endif ++ dhd_os_sdunlock(dhdp); ++ ++ AP6211_ERR("%s: WLAN OFF DONE\n", __FUNCTION__); ++ /* App can now remove power from device */ ++ } else ++ bcmerror = BCME_SDIO_ERROR; ++ } else { ++ /* App must have restored power to device before calling */ ++ ++ AP6211_ERR("%s: WLAN ON\n", __FUNCTION__); ++ ++ if (bus->dhd->dongle_reset) { ++ /* Turn on WLAN */ ++#ifdef DHDTHREAD ++ dhd_os_sdlock(dhdp); ++#endif /* DHDTHREAD */ ++ /* Reset SD client */ ++ bcmsdh_reset(bus->sdh); ++ ++ /* Attempt to re-attach & download */ ++ if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh, ++ (uint32 *)SI_ENUM_BASE, ++ bus->cl_devid)) { ++ /* Attempt to download binary to the dongle */ ++ COPY_FW_PATH_BY_CHIP(bus, fw_path, firmware_path); // terence ++ if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) && ++ dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) { ++ ++ /* Re-init bus, enable F2 transfer */ ++ bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); ++ if (bcmerror == BCME_OK) { ++#if defined(OOB_INTR_ONLY) ++ bcmsdh_set_irq(TRUE); ++ dhd_enable_oob_intr(bus, TRUE); ++#endif ++ ++ bus->dhd->dongle_reset = FALSE; ++ bus->dhd->up = TRUE; ++ ++#if !defined(IGNORE_ETH0_DOWN) ++ /* Restore flow control */ ++ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); ++#endif ++ dhd_os_wd_timer(dhdp, dhd_watchdog_ms); ++#ifdef BCMSDIOH_TXGLOM ++ if ((dhdp->busstate == DHD_BUS_DATA) && ++ bcmsdh_glom_enabled()) { ++ dhd_txglom_enable(dhdp, TRUE); ++ } ++#endif /* BCMSDIOH_TXGLOM */ ++ AP6211_ERR("%s: WLAN ON DONE\n", __FUNCTION__); ++ } else { ++ dhd_bus_stop(bus, FALSE); ++ dhdsdio_release_dongle(bus, bus->dhd->osh, ++ TRUE, FALSE); ++ } ++ } else ++ bcmerror = BCME_SDIO_ERROR; ++ } else ++ bcmerror = BCME_SDIO_ERROR; ++ ++#ifdef DHDTHREAD ++ dhd_os_sdunlock(dhdp); ++#endif /* DHDTHREAD */ ++ } else { ++ bcmerror = BCME_SDIO_ERROR; ++ AP6211_DEBUG("%s called when dongle is not in reset\n", ++ __FUNCTION__); ++ AP6211_DEBUG("Will call dhd_bus_start instead\n"); ++ sdioh_start(NULL, 1); ++#if defined(HW_OOB) ++ bcmsdh_config_hw_oob_intr(bus->sdh, bus->sih->chip); // terence 20120615: fix for OOB initial issue ++#endif ++ COPY_FW_PATH_BY_CHIP(bus, fw_path, firmware_path); ++ if ((bcmerror = dhd_bus_start(dhdp)) != 0) ++ AP6211_ERR("%s: dhd_bus_start fail with %d\n", ++ __FUNCTION__, bcmerror); ++ } ++ } ++ return bcmerror; ++} ++ ++/* Get Chip ID version */ ++uint dhd_bus_chip_id(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ ++ return bus->sih->chip; ++} ++ ++/* Get Chip Rev ID version */ ++uint dhd_bus_chiprev_id(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ ++ return bus->sih->chiprev; ++} ++ ++/* Get Chip Pkg ID version */ ++uint dhd_bus_chippkg_id(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ ++ return bus->sih->chippkg; ++} ++ ++int ++dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size) ++{ ++ dhd_bus_t *bus; ++ ++ bus = dhdp->bus; ++ return dhdsdio_membytes(bus, set, address, data, size); ++} +diff --git a/drivers/net/wireless/ap6211/dhd_wlfc.c b/drivers/net/wireless/ap6211/dhd_wlfc.c +new file mode 100755 +index 0000000..93b4ca3 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_wlfc.c +@@ -0,0 +1,2441 @@ ++/* ++ * DHD PROP_TXSTATUS Module. ++ * ++ * Copyright (C) 1999-2013, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_wlfc.c 412994 2013-07-17 12:38:03Z $ ++ * ++ */ ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#ifdef PROP_TXSTATUS ++#include ++#include ++#endif ++ ++ ++ ++ ++#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */ ++ ++#ifdef PROP_TXSTATUS ++typedef struct dhd_wlfc_commit_info { ++ uint8 needs_hdr; ++ uint8 ac_fifo_credit_spent; ++ ewlfc_packet_state_t pkt_type; ++ wlfc_mac_descriptor_t* mac_entry; ++ void* p; ++} dhd_wlfc_commit_info_t; ++#endif /* PROP_TXSTATUS */ ++ ++ ++#ifdef PROP_TXSTATUS ++ ++#define DHD_WLFC_QMON_COMPLETE(entry) ++ ++void ++dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) ++{ ++ int i; ++ uint8* ea; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhdp->wlfc_state; ++ wlfc_hanger_t* h; ++ wlfc_mac_descriptor_t* mac_table; ++ wlfc_mac_descriptor_t* interfaces; ++ char* iftypes[] = {"STA", "AP", "WDS", "p2pGO", "p2pCL"}; ++ ++ if (wlfc == NULL) { ++ bcm_bprintf(strbuf, "wlfc not initialized yet\n"); ++ return; ++ } ++ h = (wlfc_hanger_t*)wlfc->hanger; ++ if (h == NULL) { ++ bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); ++ } ++ ++ mac_table = wlfc->destination_entries.nodes; ++ interfaces = wlfc->destination_entries.interfaces; ++ bcm_bprintf(strbuf, "---- wlfc stats ----\n"); ++ if (h) { ++ bcm_bprintf(strbuf, "wlfc hanger (pushed,popped,f_push," ++ "f_pop,f_slot, pending) = (%d,%d,%d,%d,%d,%d)\n", ++ h->pushed, ++ h->popped, ++ h->failed_to_push, ++ h->failed_to_pop, ++ h->failed_slotfind, ++ (h->pushed - h->popped)); ++ } ++ ++ bcm_bprintf(strbuf, "wlfc fail(tlv,credit_rqst,mac_update,psmode_update), " ++ "(dq_full,rollback_fail) = (%d,%d,%d,%d), (%d,%d)\n", ++ wlfc->stats.tlv_parse_failed, ++ wlfc->stats.credit_request_failed, ++ wlfc->stats.mac_update_failed, ++ wlfc->stats.psmode_update_failed, ++ wlfc->stats.delayq_full_error, ++ wlfc->stats.rollback_failed); ++ ++ bcm_bprintf(strbuf, "PKTS (credit,sent) " ++ "(AC0[%d,%d],AC1[%d,%d],AC2[%d,%d],AC3[%d,%d],BC_MC[%d,%d])\n", ++ wlfc->FIFO_credit[0], wlfc->stats.send_pkts[0], ++ wlfc->FIFO_credit[1], wlfc->stats.send_pkts[1], ++ wlfc->FIFO_credit[2], wlfc->stats.send_pkts[2], ++ wlfc->FIFO_credit[3], wlfc->stats.send_pkts[3], ++ wlfc->FIFO_credit[4], wlfc->stats.send_pkts[4]); ++ ++ bcm_bprintf(strbuf, "\n"); ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ if (interfaces[i].occupied) { ++ char* iftype_desc; ++ ++ if (interfaces[i].iftype > WLC_E_IF_ROLE_P2P_CLIENT) ++ iftype_desc = "hostif_flow_state[i] == OFF) ++ ? " OFF":" ON")); ++ ++ bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ(len,state,credit)" ++ "= (%d,%s,%d)\n", ++ i, ++ interfaces[i].psq.len, ++ ((interfaces[i].state == ++ WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), ++ interfaces[i].requested_credit); ++ ++ bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ" ++ "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " ++ "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", ++ i, ++ interfaces[i].psq.q[0].len, ++ interfaces[i].psq.q[1].len, ++ interfaces[i].psq.q[2].len, ++ interfaces[i].psq.q[3].len, ++ interfaces[i].psq.q[4].len, ++ interfaces[i].psq.q[5].len, ++ interfaces[i].psq.q[6].len, ++ interfaces[i].psq.q[7].len); ++ } ++ } ++ ++ bcm_bprintf(strbuf, "\n"); ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (mac_table[i].occupied) { ++ ea = mac_table[i].ea; ++ bcm_bprintf(strbuf, "MAC_table[%d].ea = " ++ "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d \n", i, ++ ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], ++ mac_table[i].interface_id); ++ ++ bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ(len,state,credit)" ++ "= (%d,%s,%d)\n", ++ i, ++ mac_table[i].psq.len, ++ ((mac_table[i].state == ++ WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), ++ mac_table[i].requested_credit); ++#ifdef PROP_TXSTATUS_DEBUG ++ bcm_bprintf(strbuf, "MAC_table[%d]: (opened, closed) = (%d, %d)\n", ++ i, mac_table[i].opened_ct, mac_table[i].closed_ct); ++#endif ++ bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ" ++ "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " ++ "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", ++ i, ++ mac_table[i].psq.q[0].len, ++ mac_table[i].psq.q[1].len, ++ mac_table[i].psq.q[2].len, ++ mac_table[i].psq.q[3].len, ++ mac_table[i].psq.q[4].len, ++ mac_table[i].psq.q[5].len, ++ mac_table[i].psq.q[6].len, ++ mac_table[i].psq.q[7].len); ++ } ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ int avg; ++ int moving_avg = 0; ++ int moving_samples; ++ ++ if (wlfc->stats.latency_sample_count) { ++ moving_samples = sizeof(wlfc->stats.deltas)/sizeof(uint32); ++ ++ for (i = 0; i < moving_samples; i++) ++ moving_avg += wlfc->stats.deltas[i]; ++ moving_avg /= moving_samples; ++ ++ avg = (100 * wlfc->stats.total_status_latency) / ++ wlfc->stats.latency_sample_count; ++ bcm_bprintf(strbuf, "txstatus latency (average, last, moving[%d]) = " ++ "(%d.%d, %03d, %03d)\n", ++ moving_samples, avg/100, (avg - (avg/100)*100), ++ wlfc->stats.latency_most_recent, ++ moving_avg); ++ } ++ } ++ ++ bcm_bprintf(strbuf, "wlfc- fifo[0-5] credit stats: sent = (%d,%d,%d,%d,%d,%d), " ++ "back = (%d,%d,%d,%d,%d,%d)\n", ++ wlfc->stats.fifo_credits_sent[0], ++ wlfc->stats.fifo_credits_sent[1], ++ wlfc->stats.fifo_credits_sent[2], ++ wlfc->stats.fifo_credits_sent[3], ++ wlfc->stats.fifo_credits_sent[4], ++ wlfc->stats.fifo_credits_sent[5], ++ ++ wlfc->stats.fifo_credits_back[0], ++ wlfc->stats.fifo_credits_back[1], ++ wlfc->stats.fifo_credits_back[2], ++ wlfc->stats.fifo_credits_back[3], ++ wlfc->stats.fifo_credits_back[4], ++ wlfc->stats.fifo_credits_back[5]); ++ { ++ uint32 fifo_cr_sent = 0; ++ uint32 fifo_cr_acked = 0; ++ uint32 request_cr_sent = 0; ++ uint32 request_cr_ack = 0; ++ uint32 bc_mc_cr_ack = 0; ++ ++ for (i = 0; i < sizeof(wlfc->stats.fifo_credits_sent)/sizeof(uint32); i++) { ++ fifo_cr_sent += wlfc->stats.fifo_credits_sent[i]; ++ } ++ ++ for (i = 0; i < sizeof(wlfc->stats.fifo_credits_back)/sizeof(uint32); i++) { ++ fifo_cr_acked += wlfc->stats.fifo_credits_back[i]; ++ } ++ ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (wlfc->destination_entries.nodes[i].occupied) { ++ request_cr_sent += ++ wlfc->destination_entries.nodes[i].dstncredit_sent_packets; ++ } ++ } ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ if (wlfc->destination_entries.interfaces[i].occupied) { ++ request_cr_sent += ++ wlfc->destination_entries.interfaces[i].dstncredit_sent_packets; ++ } ++ } ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (wlfc->destination_entries.nodes[i].occupied) { ++ request_cr_ack += ++ wlfc->destination_entries.nodes[i].dstncredit_acks; ++ } ++ } ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ if (wlfc->destination_entries.interfaces[i].occupied) { ++ request_cr_ack += ++ wlfc->destination_entries.interfaces[i].dstncredit_acks; ++ } ++ } ++ bcm_bprintf(strbuf, "wlfc- (sent, status) => pq(%d,%d), vq(%d,%d)," ++ "other:%d, bc_mc:%d, signal-only, (sent,freed): (%d,%d)", ++ fifo_cr_sent, fifo_cr_acked, ++ request_cr_sent, request_cr_ack, ++ wlfc->destination_entries.other.dstncredit_acks, ++ bc_mc_cr_ack, ++ wlfc->stats.signal_only_pkts_sent, wlfc->stats.signal_only_pkts_freed); ++ } ++#endif /* PROP_TXSTATUS_DEBUG */ ++ bcm_bprintf(strbuf, "\n"); ++ bcm_bprintf(strbuf, "wlfc- pkt((in,2bus,txstats,hdrpull),(dropped,hdr_only,wlc_tossed)" ++ "(freed,free_err,rollback)) = " ++ "((%d,%d,%d,%d),(%d,%d,%d),(%d,%d,%d))\n", ++ wlfc->stats.pktin, ++ wlfc->stats.pkt2bus, ++ wlfc->stats.txstatus_in, ++ wlfc->stats.dhd_hdrpulls, ++ ++ wlfc->stats.pktdropped, ++ wlfc->stats.wlfc_header_only_pkt, ++ wlfc->stats.wlc_tossed_pkts, ++ ++ wlfc->stats.pkt_freed, ++ wlfc->stats.pkt_free_err, wlfc->stats.rollback); ++ ++ bcm_bprintf(strbuf, "wlfc- suppress((d11,wlc,err),enq(d11,wl,hq,mac?),retx(d11,wlc,hq)) = " ++ "((%d,%d,%d),(%d,%d,%d,%d),(%d,%d,%d))\n", ++ ++ wlfc->stats.d11_suppress, ++ wlfc->stats.wl_suppress, ++ wlfc->stats.bad_suppress, ++ ++ wlfc->stats.psq_d11sup_enq, ++ wlfc->stats.psq_wlsup_enq, ++ wlfc->stats.psq_hostq_enq, ++ wlfc->stats.mac_handle_notfound, ++ ++ wlfc->stats.psq_d11sup_retx, ++ wlfc->stats.psq_wlsup_retx, ++ wlfc->stats.psq_hostq_retx); ++ bcm_bprintf(strbuf, "wlfc- generic error: %d", wlfc->stats.generic_error); ++ ++ return; ++} ++ ++/* Create a place to store all packet pointers submitted to the firmware until ++ a status comes back, suppress or otherwise. ++ ++ hang-er: noun, a contrivance on which things are hung, as a hook. ++*/ ++static void* ++dhd_wlfc_hanger_create(osl_t *osh, int max_items) ++{ ++ int i; ++ wlfc_hanger_t* hanger; ++ ++ /* allow only up to a specific size for now */ ++ ASSERT(max_items == WLFC_HANGER_MAXITEMS); ++ ++ if ((hanger = (wlfc_hanger_t*)MALLOC(osh, WLFC_HANGER_SIZE(max_items))) == NULL) ++ return NULL; ++ ++ memset(hanger, 0, WLFC_HANGER_SIZE(max_items)); ++ hanger->max_items = max_items; ++ ++ for (i = 0; i < hanger->max_items; i++) { ++ hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } ++ return hanger; ++} ++ ++static int ++dhd_wlfc_hanger_delete(osl_t *osh, void* hanger) ++{ ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ if (h) { ++ MFREE(osh, h, WLFC_HANGER_SIZE(h->max_items)); ++ return BCME_OK; ++ } ++ return BCME_BADARG; ++} ++ ++static uint16 ++dhd_wlfc_hanger_get_free_slot(void* hanger) ++{ ++ uint32 i; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ if (h) { ++ i = h->slot_pos + 1; ++ if (i == h->max_items) { ++ i = 0; ++ } ++ while (i != h->slot_pos) { ++ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) { ++ h->slot_pos = i; ++ return (uint16)i; ++ } ++ i++; ++ if (i == h->max_items) ++ i = 0; ++ } ++ h->failed_slotfind++; ++ } ++ return WLFC_HANGER_MAXITEMS; ++} ++ ++static int ++dhd_wlfc_hanger_get_genbit(void* hanger, void* pkt, uint32 slot_id, int* gen) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ *gen = 0xff; ++ ++ /* this packet was not pushed at the time it went to the firmware */ ++ if (slot_id == WLFC_HANGER_MAXITEMS) ++ return BCME_NOTFOUND; ++ ++ if (h) { ++ if ((h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) || ++ (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { ++ *gen = h->items[slot_id].gen; ++ } ++ else { ++ rc = BCME_NOTFOUND; ++ } ++ } ++ else ++ rc = BCME_BADARG; ++ return rc; ++} ++ ++static int ++dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ if (h && (slot_id < WLFC_HANGER_MAXITEMS)) { ++ if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_FREE) { ++ h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE; ++ h->items[slot_id].pkt = pkt; ++ h->items[slot_id].identifier = slot_id; ++ h->pushed++; ++ } ++ else { ++ h->failed_to_push++; ++ rc = BCME_NOTFOUND; ++ } ++ } ++ else ++ rc = BCME_BADARG; ++ return rc; ++} ++ ++static int ++dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, int remove_from_hanger) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ /* this packet was not pushed at the time it went to the firmware */ ++ if (slot_id == WLFC_HANGER_MAXITEMS) ++ return BCME_NOTFOUND; ++ ++ if (h) { ++ if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_FREE) { ++ *pktout = h->items[slot_id].pkt; ++ if (remove_from_hanger) { ++ h->items[slot_id].state = ++ WLFC_HANGER_ITEM_STATE_FREE; ++ h->items[slot_id].pkt = NULL; ++ h->items[slot_id].identifier = 0; ++ h->items[slot_id].gen = 0xff; ++ h->popped++; ++ } ++ } ++ else { ++ h->failed_to_pop++; ++ rc = BCME_NOTFOUND; ++ } ++ } ++ else ++ rc = BCME_BADARG; ++ return rc; ++} ++ ++static int ++dhd_wlfc_hanger_mark_suppressed(void* hanger, uint32 slot_id, uint8 gen) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ /* this packet was not pushed at the time it went to the firmware */ ++ if (slot_id == WLFC_HANGER_MAXITEMS) ++ return BCME_NOTFOUND; ++ if (h) { ++ h->items[slot_id].gen = gen; ++ if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) { ++ h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED; ++ } ++ else ++ rc = BCME_BADARG; ++ } ++ else ++ rc = BCME_BADARG; ++ ++ return rc; ++} ++ ++static int ++_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void* p, bool tim_signal, ++ uint8 tim_bmp, uint8 mac_handle, uint32 htodtag) ++{ ++ uint32 wl_pktinfo = 0; ++ uint8* wlh; ++ uint8 dataOffset; ++ uint8 fillers; ++ uint8 tim_signal_len = 0; ++ ++ struct bdc_header *h; ++ ++ if (tim_signal) { ++ tim_signal_len = 1 + 1 + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; ++ } ++ ++ /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */ ++ dataOffset = WLFC_CTL_VALUE_LEN_PKTTAG + 2 + tim_signal_len; ++ fillers = ROUNDUP(dataOffset, 4) - dataOffset; ++ dataOffset += fillers; ++ ++ PKTPUSH(ctx->osh, p, dataOffset); ++ wlh = (uint8*) PKTDATA(ctx->osh, p); ++ ++ wl_pktinfo = htol32(htodtag); ++ ++ wlh[0] = WLFC_CTL_TYPE_PKTTAG; ++ wlh[1] = WLFC_CTL_VALUE_LEN_PKTTAG; ++ memcpy(&wlh[2], &wl_pktinfo, sizeof(uint32)); ++ ++ if (tim_signal_len) { ++ wlh[dataOffset - fillers - tim_signal_len ] = ++ WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP; ++ wlh[dataOffset - fillers - tim_signal_len + 1] = ++ WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; ++ wlh[dataOffset - fillers - tim_signal_len + 2] = mac_handle; ++ wlh[dataOffset - fillers - tim_signal_len + 3] = tim_bmp; ++ } ++ if (fillers) ++ memset(&wlh[dataOffset - fillers], WLFC_CTL_TYPE_FILLER, fillers); ++ ++ PKTPUSH(ctx->osh, p, BDC_HEADER_LEN); ++ h = (struct bdc_header *)PKTDATA(ctx->osh, p); ++ h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); ++ if (PKTSUMNEEDED(p)) ++ h->flags |= BDC_FLAG_SUM_NEEDED; ++ ++ ++ h->priority = (PKTPRIO(p) & BDC_PRIORITY_MASK); ++ h->flags2 = 0; ++ h->dataOffset = dataOffset >> 2; ++ BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p))); ++ return BCME_OK; ++} ++ ++static int ++_dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf) ++{ ++ struct bdc_header *h; ++ ++ if (PKTLEN(ctx->osh, pktbuf) < BDC_HEADER_LEN) { ++ AP6211_DEBUG("%s: rx data too short (%d < %d)\n", __FUNCTION__, ++ PKTLEN(ctx->osh, pktbuf), BDC_HEADER_LEN); ++ return BCME_ERROR; ++ } ++ h = (struct bdc_header *)PKTDATA(ctx->osh, pktbuf); ++ ++ /* pull BDC header */ ++ PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN); ++ ++ if (PKTLEN(ctx->osh, pktbuf) < (h->dataOffset << 2)) { ++ AP6211_DEBUG("%s: rx data too short (%d < %d)\n", __FUNCTION__, ++ PKTLEN(ctx->osh, pktbuf), (h->dataOffset << 2)); ++ return BCME_ERROR; ++ } ++ ++ /* pull wl-header */ ++ PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2)); ++ return BCME_OK; ++} ++ ++static wlfc_mac_descriptor_t* ++_dhd_wlfc_find_table_entry(athost_wl_status_info_t* ctx, void* p) ++{ ++ int i; ++ wlfc_mac_descriptor_t* table = ctx->destination_entries.nodes; ++ uint8 ifid = DHD_PKTTAG_IF(PKTTAG(p)); ++ uint8* dstn = DHD_PKTTAG_DSTN(PKTTAG(p)); ++ wlfc_mac_descriptor_t* entry = NULL; ++ int iftype = ctx->destination_entries.interfaces[ifid].iftype; ++ ++ /* Multicast destination and P2P clients get the interface entry. ++ * STA gets the interface entry if there is no exact match. For ++ * example, TDLS destinations have their own entry. ++ */ ++ if ((iftype == WLC_E_IF_ROLE_STA || ETHER_ISMULTI(dstn) || ++ iftype == WLC_E_IF_ROLE_P2P_CLIENT) && ++ (ctx->destination_entries.interfaces[ifid].occupied)) { ++ entry = &ctx->destination_entries.interfaces[ifid]; ++ } ++ ++ if (entry != NULL && ETHER_ISMULTI(dstn)) ++ return entry; ++ ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (table[i].occupied) { ++ if (table[i].interface_id == ifid) { ++ if (!memcmp(table[i].ea, dstn, ETHER_ADDR_LEN)) { ++ entry = &table[i]; ++ break; ++ } ++ } ++ } ++ } ++ ++ return entry != NULL ? entry : &ctx->destination_entries.other; ++} ++ ++static int ++_dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, ++ void* p, ewlfc_packet_state_t pkt_type, uint32 hslot) ++{ ++ /* ++ put the packet back to the head of queue ++ ++ - suppressed packet goes back to suppress sub-queue ++ - pull out the header, if new or delayed packet ++ ++ Note: hslot is used only when header removal is done. ++ */ ++ wlfc_mac_descriptor_t* entry; ++ void* pktout; ++ int rc = BCME_OK; ++ int prec; ++ ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ prec = DHD_PKTTAG_FIFO(PKTTAG(p)); ++ if (entry != NULL) { ++ if (pkt_type == eWLFC_PKTTYPE_SUPPRESSED) { ++ /* wl-header is saved for suppressed packets */ ++ if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, ((prec << 1) + 1), p) == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ rc = BCME_ERROR; ++ } ++ } ++ else { ++ /* remove header first */ ++ rc = _dhd_wlfc_pullheader(ctx, p); ++ if (rc != BCME_OK) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ /* free the hanger slot */ ++ dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); ++ PKTFREE(ctx->osh, p, TRUE); ++ ctx->stats.rollback_failed++; ++ return BCME_ERROR; ++ } ++ ++ if (pkt_type == eWLFC_PKTTYPE_DELAYED) { ++ /* delay-q packets are going to delay-q */ ++ if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, (prec << 1), p) == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ rc = BCME_ERROR; ++ } ++ } ++ ++ /* free the hanger slot */ ++ dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); ++ ++ /* decrement sequence count */ ++ WLFC_DECR_SEQCOUNT(entry, prec); ++ } ++ /* ++ if this packet did not count against FIFO credit, it must have ++ taken a requested_credit from the firmware (for pspoll etc.) ++ */ ++ if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { ++ entry->requested_credit++; ++ } ++ } ++ else { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ rc = BCME_ERROR; ++ } ++ if (rc != BCME_OK) ++ ctx->stats.rollback_failed++; ++ else ++ ctx->stats.rollback++; ++ ++ return rc; ++} ++ ++static void ++_dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint8 if_id) ++{ ++ dhd_pub_t *dhdp; ++ ++ ASSERT(ctx); ++ ++ dhdp = (dhd_pub_t *)ctx->dhdp; ++ ++ if (dhdp && dhdp->skip_fc && dhdp->skip_fc()) ++ return; ++ ++ if ((pq->len <= WLFC_FLOWCONTROL_LOWATER) && (ctx->hostif_flow_state[if_id] == ON)) { ++ /* start traffic */ ++ ctx->hostif_flow_state[if_id] = OFF; ++ /* ++ AP6211_DEBUG("qlen:%02d, if:%02d, ->OFF, start traffic %s()\n", ++ pq->len, if_id, __FUNCTION__); ++ */ ++ AP6211_DEBUG("F"); ++ ++ dhd_txflowcontrol(ctx->dhdp, if_id, OFF); ++ ++ ctx->toggle_host_if = 0; ++ } ++ if ((pq->len >= WLFC_FLOWCONTROL_HIWATER) && (ctx->hostif_flow_state[if_id] == OFF)) { ++ /* stop traffic */ ++ ctx->hostif_flow_state[if_id] = ON; ++ /* ++ AP6211_DEBUG("qlen:%02d, if:%02d, ->ON, stop traffic %s()\n", ++ pq->len, if_id, __FUNCTION__); ++ */ ++ AP6211_DEBUG("N"); ++ ++ dhd_txflowcontrol(ctx->dhdp, if_id, ON); ++ ++ ctx->host_ifidx = if_id; ++ ctx->toggle_host_if = 1; ++ } ++ ++ return; ++} ++ ++static int ++_dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, ++ uint8 ta_bmp) ++{ ++ int rc = BCME_OK; ++ void* p = NULL; ++ int dummylen = ((dhd_pub_t *)ctx->dhdp)->hdrlen+ 12; ++ ++ /* allocate a dummy packet */ ++ p = PKTGET(ctx->osh, dummylen, TRUE); ++ if (p) { ++ PKTPULL(ctx->osh, p, dummylen); ++ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0); ++ _dhd_wlfc_pushheader(ctx, p, TRUE, ta_bmp, entry->mac_handle, 0); ++ DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1); ++#ifdef PROP_TXSTATUS_DEBUG ++ ctx->stats.signal_only_pkts_sent++; ++#endif ++ rc = dhd_bus_txdata(((dhd_pub_t *)ctx->dhdp)->bus, p); ++ if (rc != BCME_OK) { ++ PKTFREE(ctx->osh, p, TRUE); ++ } ++ } ++ else { ++ AP6211_ERR("%s: couldn't allocate new %d-byte packet\n", ++ __FUNCTION__, dummylen); ++ rc = BCME_NOMEM; ++ } ++ return rc; ++} ++ ++/* Return TRUE if traffic availability changed */ ++static bool ++_dhd_wlfc_traffic_pending_check(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, ++ int prec) ++{ ++ bool rc = FALSE; ++ ++ if (entry->state == WLFC_STATE_CLOSE) { ++ if ((pktq_plen(&entry->psq, (prec << 1)) == 0) && ++ (pktq_plen(&entry->psq, ((prec << 1) + 1)) == 0)) { ++ ++ if (entry->traffic_pending_bmp & NBITVAL(prec)) { ++ rc = TRUE; ++ entry->traffic_pending_bmp = ++ entry->traffic_pending_bmp & ~ NBITVAL(prec); ++ } ++ } ++ else { ++ if (!(entry->traffic_pending_bmp & NBITVAL(prec))) { ++ rc = TRUE; ++ entry->traffic_pending_bmp = ++ entry->traffic_pending_bmp | NBITVAL(prec); ++ } ++ } ++ } ++ if (rc) { ++ /* request a TIM update to firmware at the next piggyback opportunity */ ++ if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp) { ++ entry->send_tim_signal = 1; ++ _dhd_wlfc_send_signalonly_packet(ctx, entry, entry->traffic_pending_bmp); ++ entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; ++ entry->send_tim_signal = 0; ++ } ++ else { ++ rc = FALSE; ++ } ++ } ++ return rc; ++} ++ ++static int ++_dhd_wlfc_enque_suppressed(athost_wl_status_info_t* ctx, int prec, void* p) ++{ ++ wlfc_mac_descriptor_t* entry; ++ ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ if (entry == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_NOTFOUND; ++ } ++ /* ++ - suppressed packets go to sub_queue[2*prec + 1] AND ++ - delayed packets go to sub_queue[2*prec + 0] to ensure ++ order of delivery. ++ */ ++ if (WLFC_PKTQ_PENQ(&entry->psq, ((prec << 1) + 1), p) == NULL) { ++ ctx->stats.delayq_full_error++; ++ /* AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); */ ++ AP6211_DEBUG("s"); ++ return BCME_ERROR; ++ } ++ /* A packet has been pushed, update traffic availability bitmap, if applicable */ ++ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); ++ _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p))); ++ return BCME_OK; ++} ++ ++static int ++_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, ++ wlfc_mac_descriptor_t* entry, void* p, int header_needed, uint32* slot) ++{ ++ int rc = BCME_OK; ++ int hslot = WLFC_HANGER_MAXITEMS; ++ bool send_tim_update = FALSE; ++ uint32 htod = 0; ++ uint8 free_ctr; ++ ++ *slot = hslot; ++ ++ if (entry == NULL) { ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ } ++ ++ if (entry == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_ERROR; ++ } ++ if (entry->send_tim_signal) { ++ send_tim_update = TRUE; ++ entry->send_tim_signal = 0; ++ entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; ++ } ++ if (header_needed) { ++ hslot = dhd_wlfc_hanger_get_free_slot(ctx->hanger); ++ free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); ++ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); ++ WLFC_PKTFLAG_SET_GENERATION(htod, entry->generation); ++ entry->transit_count++; ++ } ++ else { ++ hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ } ++ WLFC_PKTID_HSLOT_SET(htod, hslot); ++ WLFC_PKTID_FREERUNCTR_SET(htod, free_ctr); ++ DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1); ++ WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); ++ WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p))); ++ ++ ++ if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { ++ /* ++ Indicate that this packet is being sent in response to an ++ explicit request from the firmware side. ++ */ ++ WLFC_PKTFLAG_SET_PKTREQUESTED(htod); ++ } ++ else { ++ WLFC_PKTFLAG_CLR_PKTREQUESTED(htod); ++ } ++ if (header_needed) { ++ rc = _dhd_wlfc_pushheader(ctx, p, send_tim_update, ++ entry->traffic_lastreported_bmp, entry->mac_handle, htod); ++ if (rc == BCME_OK) { ++ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); ++ /* ++ a new header was created for this packet. ++ push to hanger slot and scrub q. Since bus ++ send succeeded, increment seq number as well. ++ */ ++ rc = dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot); ++ if (rc == BCME_OK) { ++ /* increment free running sequence count */ ++ WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); ++#ifdef PROP_TXSTATUS_DEBUG ++ ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].push_time = ++ OSL_SYSUPTIME(); ++#endif ++ } ++ else { ++ AP6211_DEBUG("%s() hanger_pushpkt() failed, rc: %d\n", ++ __FUNCTION__, rc); ++ } ++ } ++ } ++ else { ++ int gen; ++ ++ /* remove old header */ ++ rc = _dhd_wlfc_pullheader(ctx, p); ++ if (rc == BCME_OK) { ++ hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ dhd_wlfc_hanger_get_genbit(ctx->hanger, p, hslot, &gen); ++ ++ WLFC_PKTFLAG_SET_GENERATION(htod, gen); ++ free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ /* push new header */ ++ _dhd_wlfc_pushheader(ctx, p, send_tim_update, ++ entry->traffic_lastreported_bmp, entry->mac_handle, htod); ++ } ++ } ++ *slot = hslot; ++ return rc; ++} ++ ++static int ++_dhd_wlfc_is_destination_closed(athost_wl_status_info_t* ctx, ++ wlfc_mac_descriptor_t* entry, int prec) ++{ ++ if (ctx->destination_entries.interfaces[entry->interface_id].iftype == ++ WLC_E_IF_ROLE_P2P_GO) { ++ /* - destination interface is of type p2p GO. ++ For a p2pGO interface, if the destination is OPEN but the interface is ++ CLOSEd, do not send traffic. But if the dstn is CLOSEd while there is ++ destination-specific-credit left send packets. This is because the ++ firmware storing the destination-specific-requested packet in queue. ++ */ ++ if ((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && ++ (entry->requested_packet == 0)) ++ return 1; ++ } ++ /* AP, p2p_go -> unicast desc entry, STA/p2p_cl -> interface desc. entry */ ++ if (((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && ++ (entry->requested_packet == 0)) || ++ (!(entry->ac_bitmap & (1 << prec)))) ++ return 1; ++ ++ return 0; ++} ++ ++static void* ++_dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, ++ int prec, uint8* ac_credit_spent, uint8* needs_hdr, wlfc_mac_descriptor_t** entry_out) ++{ ++ wlfc_mac_descriptor_t* entry; ++ wlfc_mac_descriptor_t* table; ++ uint8 token_pos; ++ int total_entries; ++ void* p = NULL; ++ int pout; ++ int i; ++ ++ *entry_out = NULL; ++ token_pos = ctx->token_pos[prec]; ++ /* most cases a packet will count against FIFO credit */ ++ *ac_credit_spent = 1; ++ *needs_hdr = 1; ++ ++ /* search all entries, include nodes as well as interfaces */ ++ table = (wlfc_mac_descriptor_t*)&ctx->destination_entries; ++ total_entries = sizeof(ctx->destination_entries)/sizeof(wlfc_mac_descriptor_t); ++ ++ for (i = 0; i < total_entries; i++) { ++ entry = &table[(token_pos + i) % total_entries]; ++ if (entry->occupied && !entry->deleting) { ++ if (!_dhd_wlfc_is_destination_closed(ctx, entry, prec)) { ++ p = pktq_mdeq(&entry->psq, ++ /* higher precedence will be picked up first, ++ * i.e. suppressed packets before delayed ones ++ */ ++ NBITVAL((prec << 1) + 1), &pout); ++ *needs_hdr = 0; ++ ++ if (p == NULL) { ++ if (entry->suppressed == TRUE) { ++ if ((entry->suppr_transit_count <= ++ entry->suppress_count)) { ++ entry->suppressed = FALSE; ++ } else { ++ return NULL; ++ } ++ } ++ /* De-Q from delay Q */ ++ p = pktq_mdeq(&entry->psq, ++ NBITVAL((prec << 1)), ++ &pout); ++ *needs_hdr = 1; ++ } ++ ++ if (p != NULL) { ++ /* did the packet come from suppress sub-queue? */ ++ if (entry->requested_credit > 0) { ++ entry->requested_credit--; ++#ifdef PROP_TXSTATUS_DEBUG ++ entry->dstncredit_sent_packets++; ++#endif ++ /* ++ if the packet was pulled out while destination is in ++ closed state but had a non-zero packets requested, ++ then this should not count against the FIFO credit. ++ That is due to the fact that the firmware will ++ most likely hold onto this packet until a suitable ++ time later to push it to the appropriate AC FIFO. ++ */ ++ if (entry->state == WLFC_STATE_CLOSE) ++ *ac_credit_spent = 0; ++ } ++ else if (entry->requested_packet > 0) { ++ entry->requested_packet--; ++ DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p)); ++ if (entry->state == WLFC_STATE_CLOSE) ++ *ac_credit_spent = 0; ++ } ++ /* move token to ensure fair round-robin */ ++ ctx->token_pos[prec] = ++ (token_pos + i + 1) % total_entries; ++ *entry_out = entry; ++ _dhd_wlfc_flow_control_check(ctx, &entry->psq, ++ DHD_PKTTAG_IF(PKTTAG(p))); ++ /* ++ A packet has been picked up, update traffic ++ availability bitmap, if applicable ++ */ ++ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); ++ return p; ++ } ++ } ++ } ++ } ++ return NULL; ++} ++ ++void * ++_dhd_wlfc_pktq_peek_tail(struct pktq *pq, int *prec_out) ++{ ++ int prec; ++ ++ ASSERT(pq); ++ ++ if (pq->len == 0) ++ return NULL; ++ ++ for (prec = 0; prec < pq->hi_prec; prec++) ++ /* only pick packets from dealyed-q */ ++ if (((prec & 1) == 0) && pq->q[prec].head) ++ break; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ return (pq->q[prec].tail); ++} ++ ++bool ++_dhd_wlfc_prec_enq_with_drop(dhd_pub_t *dhdp, struct pktq *pq, void *pkt, int prec) ++{ ++ void *p = NULL; ++ int eprec = -1; /* precedence to evict from */ ++ ++ ASSERT(dhdp && pq && pkt); ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ /* Fast case, precedence queue is not full and we are also not ++ * exceeding total queue length ++ */ ++ if (!pktq_pfull(pq, prec) && !pktq_full(pq)) { ++ pktq_penq(pq, prec, pkt); ++ return TRUE; ++ } ++ ++ /* Determine precedence from which to evict packet, if any */ ++ if (pktq_pfull(pq, prec)) ++ eprec = prec; ++ else if (pktq_full(pq)) { ++ p = _dhd_wlfc_pktq_peek_tail(pq, &eprec); ++ if (!p) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return FALSE; ++ } ++ if ((eprec > prec) || (eprec < 0)) { ++ if (!pktq_pempty(pq, prec)) { ++ eprec = prec; ++ } else { ++ return FALSE; ++ } ++ } ++ } ++ ++ /* Evict if needed */ ++ if (eprec >= 0) { ++ /* Detect queueing to unconfigured precedence */ ++ ASSERT(!pktq_pempty(pq, eprec)); ++ /* Evict all fragmented frames */ ++ dhd_prec_drop_pkts(dhdp->osh, pq, eprec); ++ } ++ ++ /* Enqueue */ ++ p = pktq_penq(pq, prec, pkt); ++ if (!p) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static int ++_dhd_wlfc_enque_delayq(athost_wl_status_info_t* ctx, void* pktbuf, int prec) ++{ ++ wlfc_mac_descriptor_t* entry; ++ ++ if (pktbuf != NULL) { ++ entry = _dhd_wlfc_find_table_entry(ctx, pktbuf); ++ ++ if (entry == NULL) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_ERROR; ++ } ++ ++ /* ++ - suppressed packets go to sub_queue[2*prec + 1] AND ++ - delayed packets go to sub_queue[2*prec + 0] to ensure ++ order of delivery. ++ */ ++ if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, pktbuf, (prec << 1)) ++ == FALSE) { ++ AP6211_DEBUG("D"); ++ /* dhd_txcomplete(ctx->dhdp, pktbuf, FALSE); */ ++ PKTFREE(ctx->osh, pktbuf, TRUE); ++ ctx->stats.delayq_full_error++; ++ return BCME_ERROR; ++ } ++ ++ /* ++ A packet has been pushed, update traffic availability bitmap, ++ if applicable ++ */ ++ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); ++ ++ } ++ return BCME_OK; ++} ++ ++bool ifpkt_fn(void* p, int ifid) ++{ ++ return (ifid == DHD_PKTTAG_IF(PKTTAG(p))); ++} ++ ++static int ++_dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, ++ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) ++{ ++ int rc = BCME_OK; ++ ++ if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { ++ entry->occupied = 1; ++ entry->state = WLFC_STATE_OPEN; ++ entry->requested_credit = 0; ++ entry->interface_id = ifid; ++ entry->iftype = iftype; ++ entry->ac_bitmap = 0xff; /* update this when handling APSD */ ++ /* for an interface entry we may not care about the MAC address */ ++ if (ea != NULL) ++ memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); ++ pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN); ++ } ++ else if (action == eWLFC_MAC_ENTRY_ACTION_UPDATE) { ++ entry->occupied = 1; ++ entry->state = WLFC_STATE_OPEN; ++ entry->requested_credit = 0; ++ entry->interface_id = ifid; ++ entry->iftype = iftype; ++ entry->ac_bitmap = 0xff; /* update this when handling APSD */ ++ /* for an interface entry we may not care about the MAC address */ ++ if (ea != NULL) ++ memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); ++ } ++ else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) { ++ /* When the entry is deleted, the packets that are queued in the entry must be ++ cleanup. The cleanup action should be before the occupied is set as 0. The ++ flag deleting is set to avoid de-queue action when these queues are being ++ cleanup ++ */ ++ entry->deleting = 1; ++ dhd_wlfc_cleanup(ctx->dhdp, ifpkt_fn, ifid); ++ _dhd_wlfc_flow_control_check(ctx, &entry->psq, ifid); ++ entry->deleting = 0; ++ ++ entry->occupied = 0; ++ entry->suppressed = 0; ++ entry->state = WLFC_STATE_CLOSE; ++ entry->requested_credit = 0; ++ entry->transit_count = 0; ++ entry->suppr_transit_count = 0; ++ entry->suppress_count = 0; ++ memset(&entry->ea[0], 0, ETHER_ADDR_LEN); ++ ++ /* enable after packets are queued-deqeued properly. ++ pktq_flush(dhd->osh, &entry->psq, FALSE, NULL, 0); ++ */ ++ } ++ return rc; ++} ++ ++int ++_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, uint8 available_credit_map, int borrower_ac) ++{ ++ int lender_ac; ++ int rc = BCME_ERROR; ++ ++ if (ctx == NULL || available_credit_map == 0) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_BADARG; ++ } ++ ++ /* Borrow from lowest priority available AC (including BC/MC credits) */ ++ for (lender_ac = 0; lender_ac <= AC_COUNT; lender_ac++) { ++ if ((available_credit_map && (1 << lender_ac)) && ++ (ctx->FIFO_credit[lender_ac] > 0)) { ++ ctx->credits_borrowed[borrower_ac][lender_ac]++; ++ ctx->FIFO_credit[lender_ac]--; ++ rc = BCME_OK; ++ break; ++ } ++ } ++ ++ return rc; ++} ++ ++int ++dhd_wlfc_interface_entry_update(void* state, ++ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) ++{ ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ wlfc_mac_descriptor_t* entry; ++ int ret; ++ ++ if (ifid >= WLFC_MAX_IFNUM) ++ return BCME_BADARG; ++ ++ entry = &ctx->destination_entries.interfaces[ifid]; ++ ret = _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea); ++ return ret; ++} ++ ++int ++dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits) ++{ ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ ++ /* update the AC FIFO credit map */ ++ ctx->FIFO_credit[0] = credits[0]; ++ ctx->FIFO_credit[1] = credits[1]; ++ ctx->FIFO_credit[2] = credits[2]; ++ ctx->FIFO_credit[3] = credits[3]; ++ /* credit for bc/mc packets */ ++ ctx->FIFO_credit[4] = credits[4]; ++ /* credit for ATIM FIFO is not used yet. */ ++ ctx->FIFO_credit[5] = 0; ++ return BCME_OK; ++} ++ ++int ++_dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, ++ dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx) ++{ ++ uint32 hslot; ++ int rc; ++ ++ /* ++ if ac_fifo_credit_spent = 0 ++ ++ This packet will not count against the FIFO credit. ++ To ensure the txstatus corresponding to this packet ++ does not provide an implied credit (default behavior) ++ mark the packet accordingly. ++ ++ if ac_fifo_credit_spent = 1 ++ ++ This is a normal packet and it counts against the FIFO ++ credit count. ++ */ ++ DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent); ++ rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, commit_info->p, ++ commit_info->needs_hdr, &hslot); ++ ++ if (rc == BCME_OK) ++ rc = fcommit(commit_ctx, commit_info->p); ++ else ++ ctx->stats.generic_error++; ++ ++ if (rc == BCME_OK) { ++ ctx->stats.pkt2bus++; ++ if (commit_info->ac_fifo_credit_spent) { ++ ctx->stats.send_pkts[ac]++; ++ WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac); ++ } ++ } else if (rc == BCME_NORESOURCE) ++ rc = BCME_ERROR; ++ else { ++ /* ++ bus commit has failed, rollback. ++ - remove wl-header for a delayed packet ++ - save wl-header header for suppressed packets ++ */ ++ rc = _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p, ++ (commit_info->pkt_type), hslot); ++ ++ rc = BCME_ERROR; ++ } ++ ++ return rc; ++} ++ ++int ++dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx, void *pktbuf) ++{ ++ int ac; ++ int credit; ++ int rc; ++ dhd_wlfc_commit_info_t commit_info; ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ int credit_count = 0; ++ int bus_retry_count = 0; ++ uint8 ac_available = 0; /* Bitmask for 4 ACs + BC/MC */ ++ ++ if ((state == NULL) || ++ (fcommit == NULL)) { ++ AP6211_DEBUG("Error: %s():%d\n", __FUNCTION__, __LINE__); ++ return BCME_BADARG; ++ } ++ ++ memset(&commit_info, 0, sizeof(commit_info)); ++ ++ /* ++ Commit packets for regular AC traffic. Higher priority first. ++ First, use up FIFO credits available to each AC. Based on distribution ++ and credits left, borrow from other ACs as applicable ++ ++ -NOTE: ++ If the bus between the host and firmware is overwhelmed by the ++ traffic from host, it is possible that higher priority traffic ++ starves the lower priority queue. If that occurs often, we may ++ have to employ weighted round-robin or ucode scheme to avoid ++ low priority packet starvation. ++ */ ++ ++ if (pktbuf) { ++ ac = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); ++ if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(pktbuf)))) { ++ ASSERT(ac == AC_COUNT); ++ commit_info.needs_hdr = 1; ++ commit_info.mac_entry = NULL; ++ commit_info.pkt_type = eWLFC_PKTTYPE_NEW; ++ commit_info.p = pktbuf; ++ if (ctx->FIFO_credit[ac]) { ++ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, ++ fcommit, commit_ctx); ++ ++ /* Bus commits may fail (e.g. flow control); abort after retries */ ++ if (rc == BCME_OK) { ++ if (commit_info.ac_fifo_credit_spent) { ++ (void) _dhd_wlfc_borrow_credit(ctx, ++ ac_available, ac); ++ credit_count--; ++ } ++ } else { ++ bus_retry_count++; ++ if (bus_retry_count >= BUS_RETRIES) { ++ AP6211_ERR(" %s: bus error %d\n", ++ __FUNCTION__, rc); ++ return rc; ++ } ++ } ++ } ++ } ++ else { ++ /* en-queue the packets to respective queue. */ ++ rc = _dhd_wlfc_enque_delayq(ctx, pktbuf, ac); ++ } ++ } ++ ++ for (ac = AC_COUNT; ac >= 0; ac--) { ++ ++ bool bQueueIdle = TRUE; ++ ++ /* packets from delayQ with less priority are fresh and they'd need header and ++ * have no MAC entry ++ */ ++ commit_info.needs_hdr = 1; ++ commit_info.mac_entry = NULL; ++ commit_info.pkt_type = eWLFC_PKTTYPE_NEW; ++ ++ for (credit = 0; credit < ctx->FIFO_credit[ac];) { ++ commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, ++ &(commit_info.ac_fifo_credit_spent), ++ &(commit_info.needs_hdr), ++ &(commit_info.mac_entry)); ++ ++ if (commit_info.p == NULL) ++ break; ++ ++ bQueueIdle = FALSE; ++ ++ commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : ++ eWLFC_PKTTYPE_SUPPRESSED; ++ ++ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, ++ fcommit, commit_ctx); ++ ++ /* Bus commits may fail (e.g. flow control); abort after retries */ ++ if (rc == BCME_OK) { ++ if (commit_info.ac_fifo_credit_spent) { ++ credit++; ++ } ++ } ++ else { ++ bus_retry_count++; ++ if (bus_retry_count >= BUS_RETRIES) { ++ AP6211_ERR("%s: bus error %d\n", __FUNCTION__, rc); ++ ctx->FIFO_credit[ac] -= credit; ++ return rc; ++ } ++ } ++ } ++ ++ ctx->FIFO_credit[ac] -= credit; ++ ++ ++ /* If no pkts can be dequed, the credit can be borrowed */ ++ if (bQueueIdle) { ++ ac_available |= (1 << ac); ++ credit_count += ctx->FIFO_credit[ac]; ++ } ++ } ++ ++ /* We borrow only for AC_BE and only if no other traffic seen for DEFER_PERIOD ++ ++ Note that (ac_available & WLFC_AC_BE_TRAFFIC_ONLY) is done to: ++ a) ignore BC/MC for deferring borrow ++ b) ignore AC_BE being available along with other ACs ++ (this should happen only for pure BC/MC traffic) ++ ++ i.e. AC_VI, AC_VO, AC_BK all MUST be available (i.e. no traffic) and ++ we do not care if AC_BE and BC/MC are available or not ++ */ ++ if ((ac_available & WLFC_AC_BE_TRAFFIC_ONLY) == WLFC_AC_BE_TRAFFIC_ONLY) { ++ ++ if (ctx->allow_credit_borrow) { ++ ac = 1; /* Set ac to AC_BE and borrow credits */ ++ } ++ else { ++ int delta; ++ int curr_t = OSL_SYSUPTIME(); ++ ++ if (curr_t > ctx->borrow_defer_timestamp) ++ delta = curr_t - ctx->borrow_defer_timestamp; ++ else ++ delta = 0xffffffff + curr_t - ctx->borrow_defer_timestamp; ++ ++ if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) { ++ /* Reset borrow but defer to next iteration (defensive borrowing) */ ++ ctx->allow_credit_borrow = TRUE; ++ ctx->borrow_defer_timestamp = 0; ++ } ++ return BCME_OK; ++ } ++ } ++ else { ++ /* If we have multiple AC traffic, turn off borrowing, mark time and bail out */ ++ ctx->allow_credit_borrow = FALSE; ++ ctx->borrow_defer_timestamp = OSL_SYSUPTIME(); ++ return BCME_OK; ++ } ++ ++ /* At this point, borrow all credits only for "ac" (which should be set above to AC_BE) ++ Generically use "ac" only in case we extend to all ACs in future ++ */ ++ for (; (credit_count > 0);) { ++ ++ commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, ++ &(commit_info.ac_fifo_credit_spent), ++ &(commit_info.needs_hdr), ++ &(commit_info.mac_entry)); ++ if (commit_info.p == NULL) ++ break; ++ ++ commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : ++ eWLFC_PKTTYPE_SUPPRESSED; ++ ++ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, ++ fcommit, commit_ctx); ++ ++ /* Bus commits may fail (e.g. flow control); abort after retries */ ++ if (rc == BCME_OK) { ++ if (commit_info.ac_fifo_credit_spent) { ++ (void) _dhd_wlfc_borrow_credit(ctx, ac_available, ac); ++ credit_count--; ++ } ++ } ++ else { ++ bus_retry_count++; ++ if (bus_retry_count >= BUS_RETRIES) { ++ AP6211_ERR("%s: bus error %d\n", __FUNCTION__, rc); ++ return rc; ++ } ++ } ++ } ++ return BCME_OK; ++} ++ ++static uint8 ++dhd_wlfc_find_mac_desc_id_from_mac(dhd_pub_t *dhdp, uint8* ea) ++{ ++ wlfc_mac_descriptor_t* table = ++ ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes; ++ uint8 table_index; ++ ++ if (ea != NULL) { ++ for (table_index = 0; table_index < WLFC_MAC_DESC_TABLE_SIZE; table_index++) { ++ if ((memcmp(ea, &table[table_index].ea[0], ETHER_ADDR_LEN) == 0) && ++ table[table_index].occupied) ++ return table_index; ++ } ++ } ++ return WLFC_MAC_DESC_ID_INVALID; ++} ++ ++void ++dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success) ++{ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ void* p; ++ int fifo_id; ++ ++ if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) { ++#ifdef PROP_TXSTATUS_DEBUG ++ wlfc->stats.signal_only_pkts_freed++; ++#endif ++ /* is this a signal-only packet? */ ++ if (success) ++ PKTFREE(wlfc->osh, txp, TRUE); ++ return; ++ } ++ if (!success) { ++ AP6211_DEBUG("At: %s():%d, bus_complete() failure for %p, htod_tag:0x%08x\n", ++ __FUNCTION__, __LINE__, txp, DHD_PKTTAG_H2DTAG(PKTTAG(txp))); ++ dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG ++ (PKTTAG(txp))), &p, 1); ++ ++ /* indicate failure and free the packet */ ++ dhd_txcomplete(dhd, txp, FALSE); ++ ++ /* return the credit, if necessary */ ++ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(txp))) { ++ int lender, credit_returned = 0; /* Note that borrower is fifo_id */ ++ ++ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(txp)); ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; lender >= 0; lender--) { ++ if (wlfc->credits_borrowed[fifo_id][lender] > 0) { ++ wlfc->FIFO_credit[lender]++; ++ wlfc->credits_borrowed[fifo_id][lender]--; ++ credit_returned = 1; ++ break; ++ } ++ } ++ ++ if (!credit_returned) { ++ wlfc->FIFO_credit[fifo_id]++; ++ } ++ } ++ ++ PKTFREE(wlfc->osh, txp, TRUE); ++ } ++ return; ++} ++ ++static int ++dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len) ++{ ++ uint8 status_flag; ++ uint32 status; ++ int ret; ++ int remove_from_hanger = 1; ++ void* pktbuf; ++ uint8 fifo_id; ++ uint8 count = 0; ++ uint32 status_g; ++ uint32 hslot, hcnt; ++ wlfc_mac_descriptor_t* entry = NULL; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ ++ memcpy(&status, pkt_info, sizeof(uint32)); ++ status_flag = WL_TXSTATUS_GET_FLAGS(status); ++ status_g = status & 0xff000000; ++ hslot = (status & 0x00ffff00) >> 8; ++ hcnt = status & 0xff; ++ len = pkt_info[4]; ++ ++ wlfc->stats.txstatus_in++; ++ ++ if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { ++ wlfc->stats.pkt_freed++; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { ++ wlfc->stats.d11_suppress++; ++ remove_from_hanger = 0; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { ++ wlfc->stats.wl_suppress++; ++ remove_from_hanger = 0; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { ++ wlfc->stats.wlc_tossed_pkts++; ++ } ++ while (count < len) { ++ status = (status_g << 24) | (hslot << 8) | (hcnt); ++ count++; ++ hslot++; ++ hcnt++; ++ ++ ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, ++ WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); ++ if (ret != BCME_OK) { ++ /* do something */ ++ continue; ++ } ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ ++ if (!remove_from_hanger) { ++ /* this packet was suppressed */ ++ if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { ++ entry->suppressed = TRUE; ++ entry->suppress_count = pktq_mlen(&entry->psq, ++ NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); ++ entry->suppr_transit_count = entry->transit_count; ++ } ++ entry->generation = WLFC_PKTID_GEN(status); ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ uint32 new_t = OSL_SYSUPTIME(); ++ uint32 old_t; ++ uint32 delta; ++ old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ ++ WLFC_PKTID_HSLOT_GET(status)].push_time; ++ ++ ++ wlfc->stats.latency_sample_count++; ++ if (new_t > old_t) ++ delta = new_t - old_t; ++ else ++ delta = 0xffffffff + new_t - old_t; ++ wlfc->stats.total_status_latency += delta; ++ wlfc->stats.latency_most_recent = delta; ++ ++ wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; ++ if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) ++ wlfc->stats.idx_delta = 0; ++ } ++#endif /* PROP_TXSTATUS_DEBUG */ ++ ++ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); ++ ++ /* pick up the implicit credit from this packet */ ++ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { ++ if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { ++ ++ int lender, credit_returned = 0; /* Note that borrower is fifo_id */ ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; lender >= 0; lender--) { ++ if (wlfc->credits_borrowed[fifo_id][lender] > 0) { ++ wlfc->FIFO_credit[lender]++; ++ wlfc->credits_borrowed[fifo_id][lender]--; ++ credit_returned = 1; ++ break; ++ } ++ } ++ ++ if (!credit_returned) { ++ wlfc->FIFO_credit[fifo_id]++; ++ } ++ } ++ } ++ else { ++ /* ++ if this packet did not count against FIFO credit, it must have ++ taken a requested_credit from the destination entry (for pspoll etc.) ++ */ ++ if (!entry) { ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ } ++ if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) ++ entry->requested_credit++; ++#ifdef PROP_TXSTATUS_DEBUG ++ entry->dstncredit_acks++; ++#endif ++ } ++ if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || ++ (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { ++ ++ ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); ++ if (ret != BCME_OK) { ++ /* delay q is full, drop this packet */ ++ dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), ++ &pktbuf, 1); ++ ++ /* indicate failure and free the packet */ ++ dhd_txcomplete(dhd, pktbuf, FALSE); ++ entry->transit_count--; ++ DHD_WLFC_QMON_COMPLETE(entry); ++ /* packet is transmitted Successfully by dongle ++ * after first suppress. ++ */ ++ if (entry->suppressed) { ++ entry->suppr_transit_count--; ++ } ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } else { ++ /* Mark suppressed to avoid a double free during wlfc cleanup */ ++ ++ dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, ++ WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); ++ entry->suppress_count++; ++ } ++ } ++ else { ++ dhd_txcomplete(dhd, pktbuf, TRUE); ++ entry->transit_count--; ++ DHD_WLFC_QMON_COMPLETE(entry); ++ ++ /* This packet is transmitted Successfully by dongle ++ * even after first suppress. ++ */ ++ if (entry->suppressed) { ++ entry->suppr_transit_count--; ++ } ++ /* free the packet */ ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } ++ } ++ return BCME_OK; ++} ++ ++/* Handle discard or suppress indication */ ++static int ++dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info) ++{ ++ uint8 status_flag; ++ uint32 status; ++ int ret; ++ int remove_from_hanger = 1; ++ void* pktbuf; ++ uint8 fifo_id; ++ wlfc_mac_descriptor_t* entry = NULL; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ ++ memcpy(&status, pkt_info, sizeof(uint32)); ++ status_flag = WL_TXSTATUS_GET_FLAGS(status); ++ wlfc->stats.txstatus_in++; ++ ++ if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { ++ wlfc->stats.pkt_freed++; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { ++ wlfc->stats.d11_suppress++; ++ remove_from_hanger = 0; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { ++ wlfc->stats.wl_suppress++; ++ remove_from_hanger = 0; ++ } ++ ++ else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { ++ wlfc->stats.wlc_tossed_pkts++; ++ } ++ ++ ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, ++ WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); ++ if (ret != BCME_OK) { ++ /* do something */ ++ return ret; ++ } ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ ++ if (!remove_from_hanger) { ++ /* this packet was suppressed */ ++ if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { ++ entry->suppressed = TRUE; ++ entry->suppress_count = pktq_mlen(&entry->psq, ++ NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); ++ entry->suppr_transit_count = entry->transit_count; ++ } ++ entry->generation = WLFC_PKTID_GEN(status); ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ uint32 new_t = OSL_SYSUPTIME(); ++ uint32 old_t; ++ uint32 delta; ++ old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ ++ WLFC_PKTID_HSLOT_GET(status)].push_time; ++ ++ ++ wlfc->stats.latency_sample_count++; ++ if (new_t > old_t) ++ delta = new_t - old_t; ++ else ++ delta = 0xffffffff + new_t - old_t; ++ wlfc->stats.total_status_latency += delta; ++ wlfc->stats.latency_most_recent = delta; ++ ++ wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; ++ if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) ++ wlfc->stats.idx_delta = 0; ++ } ++#endif /* PROP_TXSTATUS_DEBUG */ ++ ++ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); ++ ++ /* pick up the implicit credit from this packet */ ++ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { ++ if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { ++ ++ int lender, credit_returned = 0; /* Note that borrower is fifo_id */ ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; lender >= 0; lender--) { ++ if (wlfc->credits_borrowed[fifo_id][lender] > 0) { ++ wlfc->FIFO_credit[lender]++; ++ wlfc->credits_borrowed[fifo_id][lender]--; ++ credit_returned = 1; ++ break; ++ } ++ } ++ ++ if (!credit_returned) { ++ wlfc->FIFO_credit[fifo_id]++; ++ } ++ } ++ } ++ else { ++ /* ++ if this packet did not count against FIFO credit, it must have ++ taken a requested_credit from the destination entry (for pspoll etc.) ++ */ ++ if (!entry) { ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ } ++ if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) ++ entry->requested_credit++; ++#ifdef PROP_TXSTATUS_DEBUG ++ entry->dstncredit_acks++; ++#endif ++ } ++ if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || ++ (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { ++ ++ ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); ++ if (ret != BCME_OK) { ++ /* delay q is full, drop this packet */ ++ dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), ++ &pktbuf, 1); ++ ++ /* indicate failure and free the packet */ ++ dhd_txcomplete(dhd, pktbuf, FALSE); ++ entry->transit_count--; ++ DHD_WLFC_QMON_COMPLETE(entry); ++ /* This packet is transmitted Successfully by ++ * dongle even after first suppress. ++ */ ++ if (entry->suppressed) { ++ entry->suppr_transit_count--; ++ } ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } else { ++ /* Mark suppressed to avoid a double free during wlfc cleanup */ ++ ++ dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, ++ WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); ++ entry->suppress_count++; ++ } ++ } ++ else { ++ dhd_txcomplete(dhd, pktbuf, TRUE); ++ entry->transit_count--; ++ DHD_WLFC_QMON_COMPLETE(entry); ++ ++ /* This packet is transmitted Successfully by dongle even after first suppress. */ ++ if (entry->suppressed) { ++ entry->suppr_transit_count--; ++ } ++ /* free the packet */ ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) ++{ ++ int i; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ for (i = 0; i < WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK; i++) { ++#ifdef PROP_TXSTATUS_DEBUG ++ wlfc->stats.fifo_credits_back[i] += credits[i]; ++#endif ++ /* update FIFO credits */ ++ if (wlfc->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT) ++ { ++ int lender; /* Note that borrower is i */ ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) { ++ if (wlfc->credits_borrowed[i][lender] > 0) { ++ if (credits[i] >= wlfc->credits_borrowed[i][lender]) { ++ credits[i] -= wlfc->credits_borrowed[i][lender]; ++ wlfc->FIFO_credit[lender] += ++ wlfc->credits_borrowed[i][lender]; ++ wlfc->credits_borrowed[i][lender] = 0; ++ } ++ else { ++ wlfc->credits_borrowed[i][lender] -= credits[i]; ++ wlfc->FIFO_credit[lender] += credits[i]; ++ credits[i] = 0; ++ } ++ } ++ } ++ ++ /* If we have more credits left over, these must belong to the AC */ ++ if (credits[i] > 0) { ++ wlfc->FIFO_credit[i] += credits[i]; ++ } ++ } ++ } ++ ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value) ++{ ++ uint32 timestamp; ++ ++ (void)dhd; ++ ++ bcopy(&value[2], ×tamp, sizeof(uint32)); ++ AP6211_DEBUG("RXPKT: SEQ: %d, timestamp %d\n", value[1], timestamp); ++ return BCME_OK; ++} ++ ++ ++static int ++dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi) ++{ ++ (void)dhd; ++ (void)rssi; ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_mac_table_update(dhd_pub_t *dhd, uint8* value, uint8 type) ++{ ++ int rc; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ uint8 existing_index; ++ uint8 table_index; ++ uint8 ifid; ++ uint8* ea; ++ ++ AP6211_DEBUG("%s(), mac [%02x:%02x:%02x:%02x:%02x:%02x],%s,idx:%d,id:0x%02x\n", ++ __FUNCTION__, value[2], value[3], value[4], value[5], value[6], value[7], ++ ((type == WLFC_CTL_TYPE_MACDESC_ADD) ? "ADD":"DEL"), ++ WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]), value[0]); ++ ++ table = wlfc->destination_entries.nodes; ++ table_index = WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]); ++ ifid = value[1]; ++ ea = &value[2]; ++ ++ if (type == WLFC_CTL_TYPE_MACDESC_ADD) { ++ existing_index = dhd_wlfc_find_mac_desc_id_from_mac(dhd, &value[2]); ++ if (existing_index == WLFC_MAC_DESC_ID_INVALID) { ++ /* this MAC entry does not exist, create one */ ++ if (!table[table_index].occupied) { ++ table[table_index].mac_handle = value[0]; ++ rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], ++ eWLFC_MAC_ENTRY_ACTION_ADD, ifid, ++ wlfc->destination_entries.interfaces[ifid].iftype, ++ ea); ++ } ++ else { ++ /* the space should have been empty, but it's not */ ++ wlfc->stats.mac_update_failed++; ++ } ++ } ++ else { ++ /* ++ there is an existing entry, move it to new index ++ if necessary. ++ */ ++ if (existing_index != table_index) { ++ /* if we already have an entry, free the old one */ ++ table[existing_index].occupied = 0; ++ table[existing_index].state = WLFC_STATE_CLOSE; ++ table[existing_index].requested_credit = 0; ++ table[existing_index].interface_id = 0; ++ /* enable after packets are queued-deqeued properly. ++ pktq_flush(dhd->osh, &table[existing_index].psq, FALSE, NULL, 0); ++ */ ++ } ++ } ++ } ++ if (type == WLFC_CTL_TYPE_MACDESC_DEL) { ++ if (table[table_index].occupied) { ++ rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], ++ eWLFC_MAC_ENTRY_ACTION_DEL, ifid, ++ wlfc->destination_entries.interfaces[ifid].iftype, ++ ea); ++ } ++ else { ++ /* the space should have been occupied, but it's not */ ++ wlfc->stats.mac_update_failed++; ++ } ++ } ++ BCM_REFERENCE(rc); ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type) ++{ ++ /* Handle PS on/off indication */ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_mac_descriptor_t* desc; ++ uint8 mac_handle = value[0]; ++ int i; ++ ++ table = wlfc->destination_entries.nodes; ++ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; ++ if (desc->occupied) { ++ /* a fresh PS mode should wipe old ps credits? */ ++ desc->requested_credit = 0; ++ if (type == WLFC_CTL_TYPE_MAC_OPEN) { ++ desc->state = WLFC_STATE_OPEN; ++ DHD_WLFC_CTRINC_MAC_OPEN(desc); ++ } ++ else { ++ desc->state = WLFC_STATE_CLOSE; ++ DHD_WLFC_CTRINC_MAC_CLOSE(desc); ++ /* ++ Indicate to firmware if there is any traffic pending. ++ */ ++ for (i = AC_BE; i < AC_COUNT; i++) { ++ _dhd_wlfc_traffic_pending_check(wlfc, desc, i); ++ } ++ } ++ } ++ else { ++ wlfc->stats.psmode_update_failed++; ++ } ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type) ++{ ++ /* Handle PS on/off indication */ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ uint8 if_id = value[0]; ++ ++ if (if_id < WLFC_MAX_IFNUM) { ++ table = wlfc->destination_entries.interfaces; ++ if (table[if_id].occupied) { ++ if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) { ++ table[if_id].state = WLFC_STATE_OPEN; ++ /* AP6211_DEBUG("INTERFACE[%d] OPEN\n", if_id); */ ++ } ++ else { ++ table[if_id].state = WLFC_STATE_CLOSE; ++ /* AP6211_DEBUG("INTERFACE[%d] CLOSE\n", if_id); */ ++ } ++ return BCME_OK; ++ } ++ } ++ wlfc->stats.interface_update_failed++; ++ ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_credit_request(dhd_pub_t *dhd, uint8* value) ++{ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_mac_descriptor_t* desc; ++ uint8 mac_handle; ++ uint8 credit; ++ ++ table = wlfc->destination_entries.nodes; ++ mac_handle = value[1]; ++ credit = value[0]; ++ ++ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; ++ if (desc->occupied) { ++ desc->requested_credit = credit; ++ ++ desc->ac_bitmap = value[2]; ++ } ++ else { ++ wlfc->stats.credit_request_failed++; ++ } ++ return BCME_OK; ++} ++ ++static int ++dhd_wlfc_packet_request(dhd_pub_t *dhd, uint8* value) ++{ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_mac_descriptor_t* desc; ++ uint8 mac_handle; ++ uint8 packet_count; ++ ++ table = wlfc->destination_entries.nodes; ++ mac_handle = value[1]; ++ packet_count = value[0]; ++ ++ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; ++ if (desc->occupied) { ++ desc->requested_packet = packet_count; ++ ++ desc->ac_bitmap = value[2]; ++ } ++ else { ++ wlfc->stats.packet_request_failed++; ++ } ++ return BCME_OK; ++} ++ ++static void ++dhd_wlfc_reorderinfo_indicate(uint8 *val, uint8 len, uchar *info_buf, uint *info_len) ++{ ++ if (info_len) { ++ if (info_buf) { ++ bcopy(val, info_buf, len); ++ *info_len = len; ++ } ++ else ++ *info_len = 0; ++ } ++} ++ ++int ++dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar *reorder_info_buf, ++ uint *reorder_info_len) ++{ ++ uint8 type, len; ++ uint8* value; ++ uint8* tmpbuf; ++ uint16 remainder = tlv_hdr_len; ++ uint16 processed = 0; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ tmpbuf = (uint8*)PKTDATA(dhd->osh, pktbuf); ++ if (remainder) { ++ while ((processed < (WLFC_MAX_PENDING_DATALEN * 2)) && (remainder > 0)) { ++ type = tmpbuf[processed]; ++ if (type == WLFC_CTL_TYPE_FILLER) { ++ remainder -= 1; ++ processed += 1; ++ continue; ++ } ++ ++ len = tmpbuf[processed + 1]; ++ value = &tmpbuf[processed + 2]; ++ ++ if (remainder < (2 + len)) ++ break; ++ ++ remainder -= 2 + len; ++ processed += 2 + len; ++ if (type == WLFC_CTL_TYPE_TXSTATUS) ++ dhd_wlfc_txstatus_update(dhd, value); ++ if (type == WLFC_CTL_TYPE_COMP_TXSTATUS) ++ dhd_wlfc_compressed_txstatus_update(dhd, value, len); ++ ++ else if (type == WLFC_CTL_TYPE_HOST_REORDER_RXPKTS) ++ dhd_wlfc_reorderinfo_indicate(value, len, reorder_info_buf, ++ reorder_info_len); ++ else if (type == WLFC_CTL_TYPE_FIFO_CREDITBACK) ++ dhd_wlfc_fifocreditback_indicate(dhd, value); ++ ++ else if (type == WLFC_CTL_TYPE_RSSI) ++ dhd_wlfc_rssi_indicate(dhd, value); ++ ++ else if (type == WLFC_CTL_TYPE_MAC_REQUEST_CREDIT) ++ dhd_wlfc_credit_request(dhd, value); ++ ++ else if (type == WLFC_CTL_TYPE_MAC_REQUEST_PACKET) ++ dhd_wlfc_packet_request(dhd, value); ++ ++ else if ((type == WLFC_CTL_TYPE_MAC_OPEN) || ++ (type == WLFC_CTL_TYPE_MAC_CLOSE)) ++ dhd_wlfc_psmode_update(dhd, value, type); ++ ++ else if ((type == WLFC_CTL_TYPE_MACDESC_ADD) || ++ (type == WLFC_CTL_TYPE_MACDESC_DEL)) ++ dhd_wlfc_mac_table_update(dhd, value, type); ++ ++ else if (type == WLFC_CTL_TYPE_TRANS_ID) ++ dhd_wlfc_dbg_senum_check(dhd, value); ++ ++ else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) || ++ (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) { ++ dhd_wlfc_interface_update(dhd, value, type); ++ } ++ } ++ if (remainder != 0) { ++ /* trouble..., something is not right */ ++ wlfc->stats.tlv_parse_failed++; ++ } ++ } ++ return BCME_OK; ++} ++ ++int ++dhd_wlfc_init(dhd_pub_t *dhd) ++{ ++ char iovbuf[12]; /* Room for "tlv" + '\0' + parameter */ ++ /* enable all signals & indicate host proptxstatus logic is active */ ++ uint32 tlv = dhd->wlfc_enabled? ++ WLFC_FLAGS_RSSI_SIGNALS | ++ WLFC_FLAGS_XONXOFF_SIGNALS | ++ WLFC_FLAGS_CREDIT_STATUS_SIGNALS | ++ WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | ++ WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; ++ /* WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; */ ++ ++ ++ /* ++ try to enable/disable signaling by sending "tlv" iovar. if that fails, ++ fallback to no flow control? Print a message for now. ++ */ ++ ++ /* enable proptxtstatus signaling by default */ ++ bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); ++ if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { ++ AP6211_ERR("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n"); ++ } ++ else { ++ /* ++ Leaving the message for now, it should be removed after a while; once ++ the tlv situation is stable. ++ */ ++ AP6211_ERR("dhd_wlfc_init(): successfully %s bdcv2 tlv signaling, %d\n", ++ dhd->wlfc_enabled?"enabled":"disabled", tlv); ++ } ++ return BCME_OK; ++} ++ ++int ++dhd_wlfc_enable(dhd_pub_t *dhd) ++{ ++ int i; ++ athost_wl_status_info_t* wlfc; ++ ++ if (!dhd->wlfc_enabled || dhd->wlfc_state) ++ return BCME_OK; ++ ++ /* allocate space to track txstatus propagated from firmware */ ++ dhd->wlfc_state = MALLOC(dhd->osh, sizeof(athost_wl_status_info_t)); ++ if (dhd->wlfc_state == NULL) ++ return BCME_NOMEM; ++ ++ /* initialize state space */ ++ wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ memset(wlfc, 0, sizeof(athost_wl_status_info_t)); ++ ++ /* remember osh & dhdp */ ++ wlfc->osh = dhd->osh; ++ wlfc->dhdp = dhd; ++ ++ wlfc->hanger = ++ dhd_wlfc_hanger_create(dhd->osh, WLFC_HANGER_MAXITEMS); ++ if (wlfc->hanger == NULL) { ++ MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); ++ dhd->wlfc_state = NULL; ++ AP6211_ERR("Failed to malloc dhd->wlfc_state\n"); ++ return BCME_NOMEM; ++ } ++ ++ /* initialize all interfaces to accept traffic */ ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ wlfc->hostif_flow_state[i] = OFF; ++ } ++ ++ wlfc->destination_entries.other.state = WLFC_STATE_OPEN; ++ /* bc/mc FIFO is always open [credit aside], i.e. b[5] */ ++ wlfc->destination_entries.other.ac_bitmap = 0x1f; ++ wlfc->destination_entries.other.interface_id = 0; ++ ++ wlfc->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT; ++ ++ wlfc->allow_credit_borrow = TRUE; ++ wlfc->borrow_defer_timestamp = 0; ++ ++ return BCME_OK; ++} ++ ++/* release all packet resources */ ++void ++dhd_wlfc_cleanup(dhd_pub_t *dhd, ifpkt_cb_t fn, int arg) ++{ ++ int i; ++ int total_entries; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_hanger_t* h; ++ int prec; ++ void *pkt = NULL; ++ struct pktq *txq = NULL; ++ if (dhd->wlfc_state == NULL) ++ return; ++ /* flush bus->txq */ ++ txq = dhd_bus_txq(dhd->bus); ++ /* any in the hanger? */ ++ h = (wlfc_hanger_t*)wlfc->hanger; ++ total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t); ++ /* search all entries, include nodes as well as interfaces */ ++ table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries; ++ ++ for (i = 0; i < total_entries; i++) { ++ if (table[i].occupied && (fn == NULL || (arg == table[i].interface_id))) { ++ if (table[i].psq.len) { ++ AP6211_DEBUG("%s(): DELAYQ[%d].len = %d\n", ++ __FUNCTION__, i, table[i].psq.len); ++ /* release packets held in DELAYQ */ ++ pktq_flush(wlfc->osh, &table[i].psq, TRUE, fn, arg); ++ } ++ if (fn == NULL) ++ table[i].occupied = 0; ++ } ++ } ++ for (prec = 0; prec < txq->num_prec; prec++) { ++ pkt = pktq_pdeq_with_fn(txq, prec, fn, arg); ++ while (pkt) { ++ for (i = 0; i < h->max_items; i++) { ++ if (pkt == h->items[i].pkt) { ++ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { ++ PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } else if (h->items[i].state == ++ WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { ++ /* These are already freed from the psq */ ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } ++ break; ++ } ++ } ++ pkt = pktq_pdeq(txq, prec); ++ } ++ } ++ /* flush remained pkt in hanger queue, not in bus->txq */ ++ for (i = 0; i < h->max_items; i++) { ++ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { ++ if (fn == NULL || (*fn)(h->items[i].pkt, arg)) { ++ PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } ++ } else if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { ++ if (fn == NULL || (*fn)(h->items[i].pkt, arg)) { ++ /* These are freed from the psq so no need to free again */ ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } ++ } ++ } ++ return; ++} ++ ++void ++dhd_wlfc_deinit(dhd_pub_t *dhd) ++{ ++ /* cleanup all psq related resources */ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) ++ dhd->wlfc_state; ++ ++ dhd_os_wlfc_block(dhd); ++ if (dhd->wlfc_state == NULL) { ++ dhd_os_wlfc_unblock(dhd); ++ return; ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ int i; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; ++ for (i = 0; i < h->max_items; i++) { ++ if (h->items[i].state != WLFC_HANGER_ITEM_STATE_FREE) { ++ AP6211_DEBUG("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n", ++ __FUNCTION__, i, h->items[i].pkt, ++ DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt))); ++ } ++ } ++ } ++#endif ++ /* delete hanger */ ++ dhd_wlfc_hanger_delete(dhd->osh, wlfc->hanger); ++ ++ /* free top structure */ ++ MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); ++ dhd->wlfc_state = NULL; ++ dhd_os_wlfc_unblock(dhd); ++ ++ return; ++} ++#endif /* PROP_TXSTATUS */ +diff --git a/drivers/net/wireless/ap6211/dhd_wlfc.h b/drivers/net/wireless/ap6211/dhd_wlfc.h +new file mode 100755 +index 0000000..42b350c +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dhd_wlfc.h +@@ -0,0 +1,288 @@ ++/* ++* Copyright (C) 1999-2012, Broadcom Corporation ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2 (the "GPL"), ++* available at http://www.broadcom.com/licenses/GPLv2.php, with the ++* following added to such license: ++* ++* As a special exception, the copyright holders of this software give you ++* permission to link this software with independent modules, and to copy and ++* distribute the resulting executable under terms of your choice, provided that ++* you also meet, for each linked independent module, the terms and conditions of ++* the license of that module. An independent module is a module which is not ++* derived from this software. The special exception does not apply to any ++* modifications of the software. ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a license ++* other than the GPL, without Broadcom's express prior written consent. ++* $Id: dhd_wlfc.h 361006 2012-10-05 07:45:51Z $ ++* ++*/ ++#ifndef __wlfc_host_driver_definitions_h__ ++#define __wlfc_host_driver_definitions_h__ ++ ++/* 16 bits will provide an absolute max of 65536 slots */ ++#define WLFC_HANGER_MAXITEMS 1024 ++ ++#define WLFC_HANGER_ITEM_STATE_FREE 1 ++#define WLFC_HANGER_ITEM_STATE_INUSE 2 ++#define WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3 ++#define WLFC_PKTID_HSLOT_MASK 0xffff /* allow 16 bits only */ ++#define WLFC_PKTID_HSLOT_SHIFT 8 ++ ++/* x -> TXSTATUS TAG to/from firmware */ ++#define WLFC_PKTID_HSLOT_GET(x) \ ++ (((x) >> WLFC_PKTID_HSLOT_SHIFT) & WLFC_PKTID_HSLOT_MASK) ++#define WLFC_PKTID_HSLOT_SET(var, slot) \ ++ ((var) = ((var) & ~(WLFC_PKTID_HSLOT_MASK << WLFC_PKTID_HSLOT_SHIFT)) | \ ++ (((slot) & WLFC_PKTID_HSLOT_MASK) << WLFC_PKTID_HSLOT_SHIFT)) ++ ++#define WLFC_PKTID_FREERUNCTR_MASK 0xff ++ ++#define WLFC_PKTID_FREERUNCTR_GET(x) ((x) & WLFC_PKTID_FREERUNCTR_MASK) ++#define WLFC_PKTID_FREERUNCTR_SET(var, ctr) \ ++ ((var) = (((var) & ~WLFC_PKTID_FREERUNCTR_MASK) | \ ++ (((ctr) & WLFC_PKTID_FREERUNCTR_MASK)))) ++ ++#define WLFC_PKTQ_PENQ(pq, prec, p) ((pktq_full((pq)) || pktq_pfull((pq), (prec)))? \ ++ NULL : pktq_penq((pq), (prec), (p))) ++#define WLFC_PKTQ_PENQ_HEAD(pq, prec, p) ((pktq_full((pq)) || pktq_pfull((pq), (prec))) ? \ ++ NULL : pktq_penq_head((pq), (prec), (p))) ++ ++typedef enum ewlfc_packet_state { ++ eWLFC_PKTTYPE_NEW, ++ eWLFC_PKTTYPE_DELAYED, ++ eWLFC_PKTTYPE_SUPPRESSED, ++ eWLFC_PKTTYPE_MAX ++} ewlfc_packet_state_t; ++ ++typedef enum ewlfc_mac_entry_action { ++ eWLFC_MAC_ENTRY_ACTION_ADD, ++ eWLFC_MAC_ENTRY_ACTION_DEL, ++ eWLFC_MAC_ENTRY_ACTION_UPDATE, ++ eWLFC_MAC_ENTRY_ACTION_MAX ++} ewlfc_mac_entry_action_t; ++ ++typedef struct wlfc_hanger_item { ++ uint8 state; ++ uint8 gen; ++ uint8 pad[2]; ++ uint32 identifier; ++ void* pkt; ++#ifdef PROP_TXSTATUS_DEBUG ++ uint32 push_time; ++#endif ++} wlfc_hanger_item_t; ++ ++typedef struct wlfc_hanger { ++ int max_items; ++ uint32 pushed; ++ uint32 popped; ++ uint32 failed_to_push; ++ uint32 failed_to_pop; ++ uint32 failed_slotfind; ++ wlfc_hanger_item_t items[1]; ++ uint32 slot_pos; ++} wlfc_hanger_t; ++ ++#define WLFC_HANGER_SIZE(n) ((sizeof(wlfc_hanger_t) - \ ++ sizeof(wlfc_hanger_item_t)) + ((n)*sizeof(wlfc_hanger_item_t))) ++ ++#define WLFC_STATE_OPEN 1 ++#define WLFC_STATE_CLOSE 2 ++ ++#define WLFC_PSQ_PREC_COUNT ((AC_COUNT + 1) * 2) /* 2 for each AC traffic and bc/mc */ ++ ++#define WLFC_PSQ_LEN 2048 ++ ++#define WLFC_SENDQ_LEN 256 ++ ++ ++#define WLFC_FLOWCONTROL_HIWATER (2048 - 256) ++#define WLFC_FLOWCONTROL_LOWATER 256 ++ ++ ++typedef struct wlfc_mac_descriptor { ++ uint8 occupied; ++ uint8 interface_id; ++ uint8 iftype; ++ uint8 state; ++ uint8 ac_bitmap; /* for APSD */ ++ uint8 requested_credit; ++ uint8 requested_packet; ++ uint8 ea[ETHER_ADDR_LEN]; ++ /* ++ maintain (MAC,AC) based seq count for ++ packets going to the device. As well as bc/mc. ++ */ ++ uint8 seq[AC_COUNT + 1]; ++ uint8 generation; ++ struct pktq psq; ++ /* The AC pending bitmap that was reported to the fw at last change */ ++ uint8 traffic_lastreported_bmp; ++ /* The new AC pending bitmap */ ++ uint8 traffic_pending_bmp; ++ /* 1= send on next opportunity */ ++ uint8 send_tim_signal; ++ uint8 mac_handle; ++ uint transit_count; ++ uint suppr_transit_count; ++ uint suppress_count; ++ uint8 suppressed; ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ uint32 dstncredit_sent_packets; ++ uint32 dstncredit_acks; ++ uint32 opened_ct; ++ uint32 closed_ct; ++#endif ++} wlfc_mac_descriptor_t; ++ ++#define WLFC_DECR_SEQCOUNT(entry, prec) do { if (entry->seq[(prec)] == 0) {\ ++ entry->seq[prec] = 0xff; } else entry->seq[prec]--;} while (0) ++ ++#define WLFC_INCR_SEQCOUNT(entry, prec) entry->seq[(prec)]++ ++#define WLFC_SEQCOUNT(entry, prec) entry->seq[(prec)] ++ ++typedef struct athost_wl_stat_counters { ++ uint32 pktin; ++ uint32 pkt2bus; ++ uint32 pktdropped; ++ uint32 tlv_parse_failed; ++ uint32 rollback; ++ uint32 rollback_failed; ++ uint32 sendq_full_error; ++ uint32 delayq_full_error; ++ uint32 credit_request_failed; ++ uint32 packet_request_failed; ++ uint32 mac_update_failed; ++ uint32 psmode_update_failed; ++ uint32 interface_update_failed; ++ uint32 wlfc_header_only_pkt; ++ uint32 txstatus_in; ++ uint32 d11_suppress; ++ uint32 wl_suppress; ++ uint32 bad_suppress; ++ uint32 pkt_freed; ++ uint32 pkt_free_err; ++ uint32 psq_wlsup_retx; ++ uint32 psq_wlsup_enq; ++ uint32 psq_d11sup_retx; ++ uint32 psq_d11sup_enq; ++ uint32 psq_hostq_retx; ++ uint32 psq_hostq_enq; ++ uint32 mac_handle_notfound; ++ uint32 wlc_tossed_pkts; ++ uint32 dhd_hdrpulls; ++ uint32 generic_error; ++ /* an extra one for bc/mc traffic */ ++ uint32 sendq_pkts[AC_COUNT + 1]; ++#ifdef PROP_TXSTATUS_DEBUG ++ /* all pkt2bus -> txstatus latency accumulated */ ++ uint32 latency_sample_count; ++ uint32 total_status_latency; ++ uint32 latency_most_recent; ++ int idx_delta; ++ uint32 deltas[10]; ++ uint32 fifo_credits_sent[6]; ++ uint32 fifo_credits_back[6]; ++ uint32 dropped_qfull[6]; ++ uint32 signal_only_pkts_sent; ++ uint32 signal_only_pkts_freed; ++#endif ++} athost_wl_stat_counters_t; ++ ++#ifdef PROP_TXSTATUS_DEBUG ++#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do { \ ++ (ctx)->stats.fifo_credits_sent[(ac)]++;} while (0) ++#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do { \ ++ (ctx)->stats.fifo_credits_back[(ac)]++;} while (0) ++#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do { \ ++ (ctx)->stats.dropped_qfull[(ac)]++;} while (0) ++#else ++#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do {} while (0) ++#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do {} while (0) ++#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do {} while (0) ++#endif ++ ++#define WLFC_FCMODE_NONE 0 ++#define WLFC_FCMODE_IMPLIED_CREDIT 1 ++#define WLFC_FCMODE_EXPLICIT_CREDIT 2 ++ ++/* How long to defer borrowing in milliseconds */ ++#define WLFC_BORROW_DEFER_PERIOD_MS 100 ++ ++/* Mask to represent available ACs (note: BC/MC is ignored */ ++#define WLFC_AC_MASK 0xF ++ ++/* Mask to check for only on-going AC_BE traffic */ ++#define WLFC_AC_BE_TRAFFIC_ONLY 0xD ++ ++typedef struct athost_wl_status_info { ++ uint8 last_seqid_to_wlc; ++ ++ /* OSL handle */ ++ osl_t* osh; ++ /* dhd pub */ ++ void* dhdp; ++ ++ /* stats */ ++ athost_wl_stat_counters_t stats; ++ ++ /* the additional ones are for bc/mc and ATIM FIFO */ ++ int FIFO_credit[AC_COUNT + 2]; ++ ++ /* Credit borrow counts for each FIFO from each of the other FIFOs */ ++ int credits_borrowed[AC_COUNT + 2][AC_COUNT + 2]; ++ ++ struct pktq SENDQ; ++ ++ /* packet hanger and MAC->handle lookup table */ ++ void* hanger; ++ struct { ++ /* table for individual nodes */ ++ wlfc_mac_descriptor_t nodes[WLFC_MAC_DESC_TABLE_SIZE]; ++ /* table for interfaces */ ++ wlfc_mac_descriptor_t interfaces[WLFC_MAX_IFNUM]; ++ /* OS may send packets to unknown (unassociated) destinations */ ++ /* A place holder for bc/mc and packets to unknown destinations */ ++ wlfc_mac_descriptor_t other; ++ } destination_entries; ++ /* token position for different priority packets */ ++ uint8 token_pos[AC_COUNT+1]; ++ /* ON/OFF state for flow control to the host network interface */ ++ uint8 hostif_flow_state[WLFC_MAX_IFNUM]; ++ uint8 host_ifidx; ++ /* to flow control an OS interface */ ++ uint8 toggle_host_if; ++ ++ /* ++ Mode in which the dhd flow control shall operate. Must be set before ++ traffic starts to the device. ++ 0 - Do not do any proptxtstatus flow control ++ 1 - Use implied credit from a packet status ++ 2 - Use explicit credit ++ */ ++ uint8 proptxstatus_mode; ++ ++ /* To borrow credits */ ++ uint8 allow_credit_borrow; ++ ++ /* Timestamp to compute how long to defer borrowing for */ ++ uint32 borrow_defer_timestamp; ++ ++ bool wlfc_locked; ++} athost_wl_status_info_t; ++ ++int dhd_wlfc_enable(dhd_pub_t *dhd); ++int dhd_wlfc_interface_event(struct dhd_info *, ++ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea); ++int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data); ++int dhd_wlfc_event(struct dhd_info *dhd); ++int dhd_os_wlfc_block(dhd_pub_t *pub); ++int dhd_os_wlfc_unblock(dhd_pub_t *pub); ++ ++#endif /* __wlfc_host_driver_definitions_h__ */ +diff --git a/drivers/net/wireless/ap6211/dngl_stats.h b/drivers/net/wireless/ap6211/dngl_stats.h +new file mode 100755 +index 0000000..5e5a2e2 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dngl_stats.h +@@ -0,0 +1,43 @@ ++/* ++ * Common stats definitions for clients of dongle ++ * ports ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dngl_stats.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _dngl_stats_h_ ++#define _dngl_stats_h_ ++ ++typedef struct { ++ unsigned long rx_packets; /* total packets received */ ++ unsigned long tx_packets; /* total packets transmitted */ ++ unsigned long rx_bytes; /* total bytes received */ ++ unsigned long tx_bytes; /* total bytes transmitted */ ++ unsigned long rx_errors; /* bad packets received */ ++ unsigned long tx_errors; /* packet transmit problems */ ++ unsigned long rx_dropped; /* packets dropped by dongle */ ++ unsigned long tx_dropped; /* packets dropped by dongle */ ++ unsigned long multicast; /* multicast packets received */ ++} dngl_stats_t; ++ ++#endif /* _dngl_stats_h_ */ +diff --git a/drivers/net/wireless/ap6211/dngl_wlhdr.h b/drivers/net/wireless/ap6211/dngl_wlhdr.h +new file mode 100755 +index 0000000..0e37df6 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/dngl_wlhdr.h +@@ -0,0 +1,40 @@ ++/* ++ * Dongle WL Header definitions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dngl_wlhdr.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _dngl_wlhdr_h_ ++#define _dngl_wlhdr_h_ ++ ++typedef struct wl_header { ++ uint8 type; /* Header type */ ++ uint8 version; /* Header version */ ++ int8 rssi; /* RSSI */ ++ uint8 pad; /* Unused */ ++} wl_header_t; ++ ++#define WL_HEADER_LEN sizeof(wl_header_t) ++#define WL_HEADER_TYPE 0 ++#define WL_HEADER_VER 1 ++#endif /* _dngl_wlhdr_h_ */ +diff --git a/drivers/net/wireless/ap6211/hndpmu.c b/drivers/net/wireless/ap6211/hndpmu.c +new file mode 100755 +index 0000000..e639015 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/hndpmu.c +@@ -0,0 +1,208 @@ ++/* ++ * Misc utility routines for accessing PMU corerev specific features ++ * of the SiliconBackplane-based Broadcom chips. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: hndpmu.c 354194 2012-08-30 08:39:03Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define PMU_ERROR(args) ++ ++#define PMU_MSG(args) ++ ++/* To check in verbose debugging messages not intended ++ * to be on except on private builds. ++ */ ++#define PMU_NONE(args) ++ ++ ++/* SDIO Pad drive strength to select value mappings. ++ * The last strength value in each table must be 0 (the tri-state value). ++ */ ++typedef struct { ++ uint8 strength; /* Pad Drive Strength in mA */ ++ uint8 sel; /* Chip-specific select value */ ++} sdiod_drive_str_t; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 1 */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab1[] = { ++ {4, 0x2}, ++ {2, 0x3}, ++ {1, 0x0}, ++ {0, 0x0} }; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab2[] = { ++ {12, 0x7}, ++ {10, 0x6}, ++ {8, 0x5}, ++ {6, 0x4}, ++ {4, 0x2}, ++ {2, 0x1}, ++ {0, 0x0} }; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab3[] = { ++ {32, 0x7}, ++ {26, 0x6}, ++ {22, 0x5}, ++ {16, 0x4}, ++ {12, 0x3}, ++ {8, 0x2}, ++ {4, 0x1}, ++ {0, 0x0} }; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8v) */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = { ++ {32, 0x6}, ++ {26, 0x7}, ++ {22, 0x4}, ++ {16, 0x5}, ++ {12, 0x2}, ++ {8, 0x3}, ++ {4, 0x0}, ++ {0, 0x1} }; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */ ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */ ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = { ++ {6, 0x7}, ++ {5, 0x6}, ++ {4, 0x5}, ++ {3, 0x4}, ++ {2, 0x2}, ++ {1, 0x1}, ++ {0, 0x0} }; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */ ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab6_1v8[] = { ++ {3, 0x3}, ++ {2, 0x2}, ++ {1, 0x1}, ++ {0, 0x0} }; ++ ++#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) ++ ++void ++si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) ++{ ++ chipcregs_t *cc; ++ uint origidx, intr_val = 0; ++ sdiod_drive_str_t *str_tab = NULL; ++ uint32 str_mask = 0; ++ uint32 str_shift = 0; ++ ++ if (!(sih->cccaps & CC_CAP_PMU)) { ++ return; ++ } ++ ++ /* Remember original core before switch to chipc */ ++ cc = (chipcregs_t *) si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val); ++ ++ switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) { ++ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab1; ++ str_mask = 0x30000000; ++ str_shift = 28; ++ break; ++ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2): ++ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3): ++ case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4): ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2; ++ str_mask = 0x00003800; ++ str_shift = 11; ++ break; ++ case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): ++ case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11): ++ if (sih->pmurev == 8) { ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3; ++ } ++ else if (sih->pmurev == 11) { ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; ++ } ++ str_mask = 0x00003800; ++ str_shift = 11; ++ break; ++ case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; ++ str_mask = 0x00003800; ++ str_shift = 11; ++ break; ++ case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8; ++ str_mask = 0x00003800; ++ str_shift = 11; ++ break; ++ case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab6_1v8; ++ str_mask = 0x00001800; ++ str_shift = 11; ++ break; ++ default: ++ PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", ++ bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev)); ++ ++ break; ++ } ++ ++ if (str_tab != NULL && cc != NULL) { ++ uint32 cc_data_temp; ++ int i; ++ ++ /* Pick the lowest available drive strength equal or greater than the ++ * requested strength. Drive strength of 0 requests tri-state. ++ */ ++ for (i = 0; drivestrength < str_tab[i].strength; i++) ++ ; ++ ++ if (i > 0 && drivestrength > str_tab[i].strength) ++ i--; ++ ++ W_REG(osh, &cc->chipcontrol_addr, 1); ++ cc_data_temp = R_REG(osh, &cc->chipcontrol_data); ++ cc_data_temp &= ~str_mask; ++ cc_data_temp |= str_tab[i].sel << str_shift; ++ W_REG(osh, &cc->chipcontrol_data, cc_data_temp); ++ ++ PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n", ++ drivestrength, str_tab[i].strength)); ++ } ++ ++ /* Return to original core */ ++ si_restore_core(sih, origidx, intr_val); ++} +diff --git a/drivers/net/wireless/ap6211/include/Makefile b/drivers/net/wireless/ap6211/include/Makefile +new file mode 100755 +index 0000000..8483b54 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/Makefile +@@ -0,0 +1,54 @@ ++#!/bin/bash ++# ++# This script serves following purpose: ++# ++# 1. It generates native version information by querying ++# automerger maintained database to see where src/include ++# came from ++# 2. For select components, as listed in compvers.sh ++# it generates component version files ++# ++# Copyright 2005, Broadcom, Inc. ++# ++# $Id: Makefile 241686 2011-02-19 00:22:45Z prakashd $ ++# ++ ++SRCBASE := .. ++ ++TARGETS := epivers.h ++ ++ifdef VERBOSE ++export VERBOSE ++endif ++ ++all release: epivers compvers ++ ++# Generate epivers.h for native branch version ++epivers: ++ bash epivers.sh ++ ++# Generate epivers.h for native branch version ++compvers: ++ @if [ -s "compvers.sh" ]; then \ ++ echo "Generating component versions, if any"; \ ++ bash compvers.sh; \ ++ else \ ++ echo "Skipping component version generation"; \ ++ fi ++ ++# Generate epivers.h for native branch version ++clean_compvers: ++ @if [ -s "compvers.sh" ]; then \ ++ echo "bash compvers.sh clean"; \ ++ bash compvers.sh clean; \ ++ else \ ++ echo "Skipping component version clean"; \ ++ fi ++ ++clean: ++ rm -f $(TARGETS) *.prev ++ ++clean_all: clean clean_compvers ++ ++.PHONY: all release clean epivers compvers clean_compvers ++ +diff --git a/drivers/net/wireless/ap6211/include/aidmp.h b/drivers/net/wireless/ap6211/include/aidmp.h +new file mode 100755 +index 0000000..d557079 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/aidmp.h +@@ -0,0 +1,375 @@ ++/* ++ * Broadcom AMBA Interconnect definitions. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: aidmp.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _AIDMP_H ++#define _AIDMP_H ++ ++/* Manufacturer Ids */ ++#define MFGID_ARM 0x43b ++#define MFGID_BRCM 0x4bf ++#define MFGID_MIPS 0x4a7 ++ ++/* Component Classes */ ++#define CC_SIM 0 ++#define CC_EROM 1 ++#define CC_CORESIGHT 9 ++#define CC_VERIF 0xb ++#define CC_OPTIMO 0xd ++#define CC_GEN 0xe ++#define CC_PRIMECELL 0xf ++ ++/* Enumeration ROM registers */ ++#define ER_EROMENTRY 0x000 ++#define ER_REMAPCONTROL 0xe00 ++#define ER_REMAPSELECT 0xe04 ++#define ER_MASTERSELECT 0xe10 ++#define ER_ITCR 0xf00 ++#define ER_ITIP 0xf04 ++ ++/* Erom entries */ ++#define ER_TAG 0xe ++#define ER_TAG1 0x6 ++#define ER_VALID 1 ++#define ER_CI 0 ++#define ER_MP 2 ++#define ER_ADD 4 ++#define ER_END 0xe ++#define ER_BAD 0xffffffff ++ ++/* EROM CompIdentA */ ++#define CIA_MFG_MASK 0xfff00000 ++#define CIA_MFG_SHIFT 20 ++#define CIA_CID_MASK 0x000fff00 ++#define CIA_CID_SHIFT 8 ++#define CIA_CCL_MASK 0x000000f0 ++#define CIA_CCL_SHIFT 4 ++ ++/* EROM CompIdentB */ ++#define CIB_REV_MASK 0xff000000 ++#define CIB_REV_SHIFT 24 ++#define CIB_NSW_MASK 0x00f80000 ++#define CIB_NSW_SHIFT 19 ++#define CIB_NMW_MASK 0x0007c000 ++#define CIB_NMW_SHIFT 14 ++#define CIB_NSP_MASK 0x00003e00 ++#define CIB_NSP_SHIFT 9 ++#define CIB_NMP_MASK 0x000001f0 ++#define CIB_NMP_SHIFT 4 ++ ++/* EROM MasterPortDesc */ ++#define MPD_MUI_MASK 0x0000ff00 ++#define MPD_MUI_SHIFT 8 ++#define MPD_MP_MASK 0x000000f0 ++#define MPD_MP_SHIFT 4 ++ ++/* EROM AddrDesc */ ++#define AD_ADDR_MASK 0xfffff000 ++#define AD_SP_MASK 0x00000f00 ++#define AD_SP_SHIFT 8 ++#define AD_ST_MASK 0x000000c0 ++#define AD_ST_SHIFT 6 ++#define AD_ST_SLAVE 0x00000000 ++#define AD_ST_BRIDGE 0x00000040 ++#define AD_ST_SWRAP 0x00000080 ++#define AD_ST_MWRAP 0x000000c0 ++#define AD_SZ_MASK 0x00000030 ++#define AD_SZ_SHIFT 4 ++#define AD_SZ_4K 0x00000000 ++#define AD_SZ_8K 0x00000010 ++#define AD_SZ_16K 0x00000020 ++#define AD_SZ_SZD 0x00000030 ++#define AD_AG32 0x00000008 ++#define AD_ADDR_ALIGN 0x00000fff ++#define AD_SZ_BASE 0x00001000 /* 4KB */ ++ ++/* EROM SizeDesc */ ++#define SD_SZ_MASK 0xfffff000 ++#define SD_SG32 0x00000008 ++#define SD_SZ_ALIGN 0x00000fff ++ ++ ++#ifndef _LANGUAGE_ASSEMBLY ++ ++typedef volatile struct _aidmp { ++ uint32 oobselina30; /* 0x000 */ ++ uint32 oobselina74; /* 0x004 */ ++ uint32 PAD[6]; ++ uint32 oobselinb30; /* 0x020 */ ++ uint32 oobselinb74; /* 0x024 */ ++ uint32 PAD[6]; ++ uint32 oobselinc30; /* 0x040 */ ++ uint32 oobselinc74; /* 0x044 */ ++ uint32 PAD[6]; ++ uint32 oobselind30; /* 0x060 */ ++ uint32 oobselind74; /* 0x064 */ ++ uint32 PAD[38]; ++ uint32 oobselouta30; /* 0x100 */ ++ uint32 oobselouta74; /* 0x104 */ ++ uint32 PAD[6]; ++ uint32 oobseloutb30; /* 0x120 */ ++ uint32 oobseloutb74; /* 0x124 */ ++ uint32 PAD[6]; ++ uint32 oobseloutc30; /* 0x140 */ ++ uint32 oobseloutc74; /* 0x144 */ ++ uint32 PAD[6]; ++ uint32 oobseloutd30; /* 0x160 */ ++ uint32 oobseloutd74; /* 0x164 */ ++ uint32 PAD[38]; ++ uint32 oobsynca; /* 0x200 */ ++ uint32 oobseloutaen; /* 0x204 */ ++ uint32 PAD[6]; ++ uint32 oobsyncb; /* 0x220 */ ++ uint32 oobseloutben; /* 0x224 */ ++ uint32 PAD[6]; ++ uint32 oobsyncc; /* 0x240 */ ++ uint32 oobseloutcen; /* 0x244 */ ++ uint32 PAD[6]; ++ uint32 oobsyncd; /* 0x260 */ ++ uint32 oobseloutden; /* 0x264 */ ++ uint32 PAD[38]; ++ uint32 oobaextwidth; /* 0x300 */ ++ uint32 oobainwidth; /* 0x304 */ ++ uint32 oobaoutwidth; /* 0x308 */ ++ uint32 PAD[5]; ++ uint32 oobbextwidth; /* 0x320 */ ++ uint32 oobbinwidth; /* 0x324 */ ++ uint32 oobboutwidth; /* 0x328 */ ++ uint32 PAD[5]; ++ uint32 oobcextwidth; /* 0x340 */ ++ uint32 oobcinwidth; /* 0x344 */ ++ uint32 oobcoutwidth; /* 0x348 */ ++ uint32 PAD[5]; ++ uint32 oobdextwidth; /* 0x360 */ ++ uint32 oobdinwidth; /* 0x364 */ ++ uint32 oobdoutwidth; /* 0x368 */ ++ uint32 PAD[37]; ++ uint32 ioctrlset; /* 0x400 */ ++ uint32 ioctrlclear; /* 0x404 */ ++ uint32 ioctrl; /* 0x408 */ ++ uint32 PAD[61]; ++ uint32 iostatus; /* 0x500 */ ++ uint32 PAD[127]; ++ uint32 ioctrlwidth; /* 0x700 */ ++ uint32 iostatuswidth; /* 0x704 */ ++ uint32 PAD[62]; ++ uint32 resetctrl; /* 0x800 */ ++ uint32 resetstatus; /* 0x804 */ ++ uint32 resetreadid; /* 0x808 */ ++ uint32 resetwriteid; /* 0x80c */ ++ uint32 PAD[60]; ++ uint32 errlogctrl; /* 0x900 */ ++ uint32 errlogdone; /* 0x904 */ ++ uint32 errlogstatus; /* 0x908 */ ++ uint32 errlogaddrlo; /* 0x90c */ ++ uint32 errlogaddrhi; /* 0x910 */ ++ uint32 errlogid; /* 0x914 */ ++ uint32 errloguser; /* 0x918 */ ++ uint32 errlogflags; /* 0x91c */ ++ uint32 PAD[56]; ++ uint32 intstatus; /* 0xa00 */ ++ uint32 PAD[255]; ++ uint32 config; /* 0xe00 */ ++ uint32 PAD[63]; ++ uint32 itcr; /* 0xf00 */ ++ uint32 PAD[3]; ++ uint32 itipooba; /* 0xf10 */ ++ uint32 itipoobb; /* 0xf14 */ ++ uint32 itipoobc; /* 0xf18 */ ++ uint32 itipoobd; /* 0xf1c */ ++ uint32 PAD[4]; ++ uint32 itipoobaout; /* 0xf30 */ ++ uint32 itipoobbout; /* 0xf34 */ ++ uint32 itipoobcout; /* 0xf38 */ ++ uint32 itipoobdout; /* 0xf3c */ ++ uint32 PAD[4]; ++ uint32 itopooba; /* 0xf50 */ ++ uint32 itopoobb; /* 0xf54 */ ++ uint32 itopoobc; /* 0xf58 */ ++ uint32 itopoobd; /* 0xf5c */ ++ uint32 PAD[4]; ++ uint32 itopoobain; /* 0xf70 */ ++ uint32 itopoobbin; /* 0xf74 */ ++ uint32 itopoobcin; /* 0xf78 */ ++ uint32 itopoobdin; /* 0xf7c */ ++ uint32 PAD[4]; ++ uint32 itopreset; /* 0xf90 */ ++ uint32 PAD[15]; ++ uint32 peripherialid4; /* 0xfd0 */ ++ uint32 peripherialid5; /* 0xfd4 */ ++ uint32 peripherialid6; /* 0xfd8 */ ++ uint32 peripherialid7; /* 0xfdc */ ++ uint32 peripherialid0; /* 0xfe0 */ ++ uint32 peripherialid1; /* 0xfe4 */ ++ uint32 peripherialid2; /* 0xfe8 */ ++ uint32 peripherialid3; /* 0xfec */ ++ uint32 componentid0; /* 0xff0 */ ++ uint32 componentid1; /* 0xff4 */ ++ uint32 componentid2; /* 0xff8 */ ++ uint32 componentid3; /* 0xffc */ ++} aidmp_t; ++ ++#endif /* _LANGUAGE_ASSEMBLY */ ++ ++/* Out-of-band Router registers */ ++#define OOB_BUSCONFIG 0x020 ++#define OOB_STATUSA 0x100 ++#define OOB_STATUSB 0x104 ++#define OOB_STATUSC 0x108 ++#define OOB_STATUSD 0x10c ++#define OOB_ENABLEA0 0x200 ++#define OOB_ENABLEA1 0x204 ++#define OOB_ENABLEA2 0x208 ++#define OOB_ENABLEA3 0x20c ++#define OOB_ENABLEB0 0x280 ++#define OOB_ENABLEB1 0x284 ++#define OOB_ENABLEB2 0x288 ++#define OOB_ENABLEB3 0x28c ++#define OOB_ENABLEC0 0x300 ++#define OOB_ENABLEC1 0x304 ++#define OOB_ENABLEC2 0x308 ++#define OOB_ENABLEC3 0x30c ++#define OOB_ENABLED0 0x380 ++#define OOB_ENABLED1 0x384 ++#define OOB_ENABLED2 0x388 ++#define OOB_ENABLED3 0x38c ++#define OOB_ITCR 0xf00 ++#define OOB_ITIPOOBA 0xf10 ++#define OOB_ITIPOOBB 0xf14 ++#define OOB_ITIPOOBC 0xf18 ++#define OOB_ITIPOOBD 0xf1c ++#define OOB_ITOPOOBA 0xf30 ++#define OOB_ITOPOOBB 0xf34 ++#define OOB_ITOPOOBC 0xf38 ++#define OOB_ITOPOOBD 0xf3c ++ ++/* DMP wrapper registers */ ++#define AI_OOBSELINA30 0x000 ++#define AI_OOBSELINA74 0x004 ++#define AI_OOBSELINB30 0x020 ++#define AI_OOBSELINB74 0x024 ++#define AI_OOBSELINC30 0x040 ++#define AI_OOBSELINC74 0x044 ++#define AI_OOBSELIND30 0x060 ++#define AI_OOBSELIND74 0x064 ++#define AI_OOBSELOUTA30 0x100 ++#define AI_OOBSELOUTA74 0x104 ++#define AI_OOBSELOUTB30 0x120 ++#define AI_OOBSELOUTB74 0x124 ++#define AI_OOBSELOUTC30 0x140 ++#define AI_OOBSELOUTC74 0x144 ++#define AI_OOBSELOUTD30 0x160 ++#define AI_OOBSELOUTD74 0x164 ++#define AI_OOBSYNCA 0x200 ++#define AI_OOBSELOUTAEN 0x204 ++#define AI_OOBSYNCB 0x220 ++#define AI_OOBSELOUTBEN 0x224 ++#define AI_OOBSYNCC 0x240 ++#define AI_OOBSELOUTCEN 0x244 ++#define AI_OOBSYNCD 0x260 ++#define AI_OOBSELOUTDEN 0x264 ++#define AI_OOBAEXTWIDTH 0x300 ++#define AI_OOBAINWIDTH 0x304 ++#define AI_OOBAOUTWIDTH 0x308 ++#define AI_OOBBEXTWIDTH 0x320 ++#define AI_OOBBINWIDTH 0x324 ++#define AI_OOBBOUTWIDTH 0x328 ++#define AI_OOBCEXTWIDTH 0x340 ++#define AI_OOBCINWIDTH 0x344 ++#define AI_OOBCOUTWIDTH 0x348 ++#define AI_OOBDEXTWIDTH 0x360 ++#define AI_OOBDINWIDTH 0x364 ++#define AI_OOBDOUTWIDTH 0x368 ++ ++ ++#define AI_IOCTRLSET 0x400 ++#define AI_IOCTRLCLEAR 0x404 ++#define AI_IOCTRL 0x408 ++#define AI_IOSTATUS 0x500 ++#define AI_RESETCTRL 0x800 ++#define AI_RESETSTATUS 0x804 ++ ++#define AI_IOCTRLWIDTH 0x700 ++#define AI_IOSTATUSWIDTH 0x704 ++ ++#define AI_RESETREADID 0x808 ++#define AI_RESETWRITEID 0x80c ++#define AI_ERRLOGCTRL 0xa00 ++#define AI_ERRLOGDONE 0xa04 ++#define AI_ERRLOGSTATUS 0xa08 ++#define AI_ERRLOGADDRLO 0xa0c ++#define AI_ERRLOGADDRHI 0xa10 ++#define AI_ERRLOGID 0xa14 ++#define AI_ERRLOGUSER 0xa18 ++#define AI_ERRLOGFLAGS 0xa1c ++#define AI_INTSTATUS 0xa00 ++#define AI_CONFIG 0xe00 ++#define AI_ITCR 0xf00 ++#define AI_ITIPOOBA 0xf10 ++#define AI_ITIPOOBB 0xf14 ++#define AI_ITIPOOBC 0xf18 ++#define AI_ITIPOOBD 0xf1c ++#define AI_ITIPOOBAOUT 0xf30 ++#define AI_ITIPOOBBOUT 0xf34 ++#define AI_ITIPOOBCOUT 0xf38 ++#define AI_ITIPOOBDOUT 0xf3c ++#define AI_ITOPOOBA 0xf50 ++#define AI_ITOPOOBB 0xf54 ++#define AI_ITOPOOBC 0xf58 ++#define AI_ITOPOOBD 0xf5c ++#define AI_ITOPOOBAIN 0xf70 ++#define AI_ITOPOOBBIN 0xf74 ++#define AI_ITOPOOBCIN 0xf78 ++#define AI_ITOPOOBDIN 0xf7c ++#define AI_ITOPRESET 0xf90 ++#define AI_PERIPHERIALID4 0xfd0 ++#define AI_PERIPHERIALID5 0xfd4 ++#define AI_PERIPHERIALID6 0xfd8 ++#define AI_PERIPHERIALID7 0xfdc ++#define AI_PERIPHERIALID0 0xfe0 ++#define AI_PERIPHERIALID1 0xfe4 ++#define AI_PERIPHERIALID2 0xfe8 ++#define AI_PERIPHERIALID3 0xfec ++#define AI_COMPONENTID0 0xff0 ++#define AI_COMPONENTID1 0xff4 ++#define AI_COMPONENTID2 0xff8 ++#define AI_COMPONENTID3 0xffc ++ ++/* resetctrl */ ++#define AIRC_RESET 1 ++ ++/* config */ ++#define AICFG_OOB 0x00000020 ++#define AICFG_IOS 0x00000010 ++#define AICFG_IOC 0x00000008 ++#define AICFG_TO 0x00000004 ++#define AICFG_ERRL 0x00000002 ++#define AICFG_RST 0x00000001 ++ ++/* bit defines for AI_OOBSELOUTB74 reg */ ++#define OOB_SEL_OUTEN_B_5 15 ++#define OOB_SEL_OUTEN_B_6 23 ++ ++#endif /* _AIDMP_H */ +diff --git a/drivers/net/wireless/ap6211/include/bcm_cfg.h b/drivers/net/wireless/ap6211/include/bcm_cfg.h +new file mode 100755 +index 0000000..ecff4f4 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcm_cfg.h +@@ -0,0 +1,29 @@ ++/* ++ * BCM common config options ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcm_cfg.h 294399 2011-11-07 03:31:22Z $ ++ */ ++ ++#ifndef _bcm_cfg_h_ ++#define _bcm_cfg_h_ ++#endif /* _bcm_cfg_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcm_mpool_pub.h b/drivers/net/wireless/ap6211/include/bcm_mpool_pub.h +new file mode 100755 +index 0000000..8fe3de7 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcm_mpool_pub.h +@@ -0,0 +1,361 @@ ++/* ++ * Memory pools library, Public interface ++ * ++ * API Overview ++ * ++ * This package provides a memory allocation subsystem based on pools of ++ * homogenous objects. ++ * ++ * Instrumentation is available for reporting memory utilization both ++ * on a per-data-structure basis and system wide. ++ * ++ * There are two main types defined in this API. ++ * ++ * pool manager: A singleton object that acts as a factory for ++ * pool allocators. It also is used for global ++ * instrumentation, such as reporting all blocks ++ * in use across all data structures. The pool manager ++ * creates and provides individual memory pools ++ * upon request to application code. ++ * ++ * memory pool: An object for allocating homogenous memory blocks. ++ * ++ * Global identifiers in this module use the following prefixes: ++ * bcm_mpm_* Memory pool manager ++ * bcm_mp_* Memory pool ++ * ++ * There are two main types of memory pools: ++ * ++ * prealloc: The contiguous memory block of objects can either be supplied ++ * by the client or malloc'ed by the memory manager. The objects are ++ * allocated out of a block of memory and freed back to the block. ++ * ++ * heap: The memory pool allocator uses the heap (malloc/free) for memory. ++ * In this case, the pool allocator is just providing statistics ++ * and instrumentation on top of the heap, without modifying the heap ++ * allocation implementation. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id$ ++ */ ++ ++#ifndef _BCM_MPOOL_PUB_H ++#define _BCM_MPOOL_PUB_H 1 ++ ++#include /* needed for uint16 */ ++ ++ ++/* ++************************************************************************** ++* ++* Type definitions, handles ++* ++************************************************************************** ++*/ ++ ++/* Forward declaration of OSL handle. */ ++struct osl_info; ++ ++/* Forward declaration of string buffer. */ ++struct bcmstrbuf; ++ ++/* ++ * Opaque type definition for the pool manager handle. This object is used for global ++ * memory pool operations such as obtaining a new pool, deleting a pool, iterating and ++ * instrumentation/debugging. ++ */ ++struct bcm_mpm_mgr; ++typedef struct bcm_mpm_mgr *bcm_mpm_mgr_h; ++ ++/* ++ * Opaque type definition for an instance of a pool. This handle is used for allocating ++ * and freeing memory through the pool, as well as management/instrumentation on this ++ * specific pool. ++ */ ++struct bcm_mp_pool; ++typedef struct bcm_mp_pool *bcm_mp_pool_h; ++ ++ ++/* ++ * To make instrumentation more readable, every memory ++ * pool must have a readable name. Pool names are up to ++ * 8 bytes including '\0' termination. (7 printable characters.) ++ */ ++#define BCM_MP_NAMELEN 8 ++ ++ ++/* ++ * Type definition for pool statistics. ++ */ ++typedef struct bcm_mp_stats { ++ char name[BCM_MP_NAMELEN]; /* Name of this pool. */ ++ unsigned int objsz; /* Object size allocated in this pool */ ++ uint16 nobj; /* Total number of objects in this pool */ ++ uint16 num_alloc; /* Number of objects currently allocated */ ++ uint16 high_water; /* Max number of allocated objects. */ ++ uint16 failed_alloc; /* Failed allocations. */ ++} bcm_mp_stats_t; ++ ++ ++/* ++************************************************************************** ++* ++* API Routines on the pool manager. ++* ++************************************************************************** ++*/ ++ ++/* ++ * bcm_mpm_init() - initialize the whole memory pool system. ++ * ++ * Parameters: ++ * osh: INPUT Operating system handle. Needed for heap memory allocation. ++ * max_pools: INPUT Maximum number of mempools supported. ++ * mgr: OUTPUT The handle is written with the new pools manager object/handle. ++ * ++ * Returns: ++ * BCME_OK Object initialized successfully. May be used. ++ * BCME_NOMEM Initialization failed due to no memory. Object must not be used. ++ */ ++int bcm_mpm_init(struct osl_info *osh, int max_pools, bcm_mpm_mgr_h *mgrp); ++ ++ ++/* ++ * bcm_mpm_deinit() - de-initialize the whole memory pool system. ++ * ++ * Parameters: ++ * mgr: INPUT Pointer to pool manager handle. ++ * ++ * Returns: ++ * BCME_OK Memory pool manager successfully de-initialized. ++ * other Indicated error occured during de-initialization. ++ */ ++int bcm_mpm_deinit(bcm_mpm_mgr_h *mgrp); ++ ++/* ++ * bcm_mpm_create_prealloc_pool() - Create a new pool for fixed size objects. The ++ * pool uses a contiguous block of pre-alloced ++ * memory. The memory block may either be provided ++ * by the client or dynamically allocated by the ++ * pool manager. ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pool manager ++ * obj_sz: INPUT Size of objects that will be allocated by the new pool ++ * Must be >= sizeof(void *). ++ * nobj: INPUT Maximum number of concurrently existing objects to support ++ * memstart INPUT Pointer to the memory to use, or NULL to malloc() ++ * memsize INPUT Number of bytes referenced from memstart (for error checking). ++ * Must be 0 if 'memstart' is NULL. ++ * poolname INPUT For instrumentation, the name of the pool ++ * newp: OUTPUT The handle for the new pool, if creation is successful ++ * ++ * Returns: ++ * BCME_OK Pool created ok. ++ * other Pool not created due to indicated error. newpoolp set to NULL. ++ * ++ * ++ */ ++int bcm_mpm_create_prealloc_pool(bcm_mpm_mgr_h mgr, ++ unsigned int obj_sz, ++ int nobj, ++ void *memstart, ++ unsigned int memsize, ++ char poolname[BCM_MP_NAMELEN], ++ bcm_mp_pool_h *newp); ++ ++ ++/* ++ * bcm_mpm_delete_prealloc_pool() - Delete a memory pool. This should only be called after ++ * all memory objects have been freed back to the pool. ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pools manager ++ * pool: INPUT The handle of the pool to delete ++ * ++ * Returns: ++ * BCME_OK Pool deleted ok. ++ * other Pool not deleted due to indicated error. ++ * ++ */ ++int bcm_mpm_delete_prealloc_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); ++ ++/* ++ * bcm_mpm_create_heap_pool() - Create a new pool for fixed size objects. The memory ++ * pool allocator uses the heap (malloc/free) for memory. ++ * In this case, the pool allocator is just providing ++ * statistics and instrumentation on top of the heap, ++ * without modifying the heap allocation implementation. ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pool manager ++ * obj_sz: INPUT Size of objects that will be allocated by the new pool ++ * poolname INPUT For instrumentation, the name of the pool ++ * newp: OUTPUT The handle for the new pool, if creation is successful ++ * ++ * Returns: ++ * BCME_OK Pool created ok. ++ * other Pool not created due to indicated error. newpoolp set to NULL. ++ * ++ * ++ */ ++int bcm_mpm_create_heap_pool(bcm_mpm_mgr_h mgr, unsigned int obj_sz, ++ char poolname[BCM_MP_NAMELEN], ++ bcm_mp_pool_h *newp); ++ ++ ++/* ++ * bcm_mpm_delete_heap_pool() - Delete a memory pool. This should only be called after ++ * all memory objects have been freed back to the pool. ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pools manager ++ * pool: INPUT The handle of the pool to delete ++ * ++ * Returns: ++ * BCME_OK Pool deleted ok. ++ * other Pool not deleted due to indicated error. ++ * ++ */ ++int bcm_mpm_delete_heap_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); ++ ++ ++/* ++ * bcm_mpm_stats() - Return stats for all pools ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pools manager ++ * stats: OUTPUT Array of pool statistics. ++ * nentries: MOD Max elements in 'stats' array on INPUT. Actual number ++ * of array elements copied to 'stats' on OUTPUT. ++ * ++ * Returns: ++ * BCME_OK Ok ++ * other Error getting stats. ++ * ++ */ ++int bcm_mpm_stats(bcm_mpm_mgr_h mgr, bcm_mp_stats_t *stats, int *nentries); ++ ++ ++/* ++ * bcm_mpm_dump() - Display statistics on all pools ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pools manager ++ * b: OUTPUT Output buffer. ++ * ++ * Returns: ++ * BCME_OK Ok ++ * other Error during dump. ++ * ++ */ ++int bcm_mpm_dump(bcm_mpm_mgr_h mgr, struct bcmstrbuf *b); ++ ++ ++/* ++ * bcm_mpm_get_obj_size() - The size of memory objects may need to be padded to ++ * compensate for alignment requirements of the objects. ++ * This function provides the padded object size. If clients ++ * pre-allocate a memory slab for a memory pool, the ++ * padded object size should be used by the client to allocate ++ * the memory slab (in order to provide sufficent space for ++ * the maximum number of objects). ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pools manager. ++ * obj_sz: INPUT Input object size. ++ * padded_obj_sz: OUTPUT Padded object size. ++ * ++ * Returns: ++ * BCME_OK Ok ++ * BCME_BADARG Bad arguments. ++ * ++ */ ++int bcm_mpm_get_obj_size(bcm_mpm_mgr_h mgr, unsigned int obj_sz, unsigned int *padded_obj_sz); ++ ++ ++/* ++*************************************************************************** ++* ++* API Routines on a specific pool. ++* ++*************************************************************************** ++*/ ++ ++ ++/* ++ * bcm_mp_alloc() - Allocate a memory pool object. ++ * ++ * Parameters: ++ * pool: INPUT The handle to the pool. ++ * ++ * Returns: ++ * A pointer to the new object. NULL on error. ++ * ++ */ ++void* bcm_mp_alloc(bcm_mp_pool_h pool); ++ ++/* ++ * bcm_mp_free() - Free a memory pool object. ++ * ++ * Parameters: ++ * pool: INPUT The handle to the pool. ++ * objp: INPUT A pointer to the object to free. ++ * ++ * Returns: ++ * BCME_OK Ok ++ * other Error during free. ++ * ++ */ ++int bcm_mp_free(bcm_mp_pool_h pool, void *objp); ++ ++/* ++ * bcm_mp_stats() - Return stats for this pool ++ * ++ * Parameters: ++ * pool: INPUT The handle to the pool ++ * stats: OUTPUT Pool statistics ++ * ++ * Returns: ++ * BCME_OK Ok ++ * other Error getting statistics. ++ * ++ */ ++int bcm_mp_stats(bcm_mp_pool_h pool, bcm_mp_stats_t *stats); ++ ++ ++/* ++ * bcm_mp_dump() - Dump a pool ++ * ++ * Parameters: ++ * pool: INPUT The handle to the pool ++ * b OUTPUT Output buffer ++ * ++ * Returns: ++ * BCME_OK Ok ++ * other Error during dump. ++ * ++ */ ++int bcm_mp_dump(bcm_mp_pool_h pool, struct bcmstrbuf *b); ++ ++ ++#endif /* _BCM_MPOOL_PUB_H */ +diff --git a/drivers/net/wireless/ap6211/include/bcmcdc.h b/drivers/net/wireless/ap6211/include/bcmcdc.h +new file mode 100755 +index 0000000..a1d1271 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmcdc.h +@@ -0,0 +1,132 @@ ++/* ++ * CDC network driver ioctl/indication encoding ++ * Broadcom 802.11abg Networking Device Driver ++ * ++ * Definitions subject to change without notice. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmcdc.h 318308 2012-03-02 02:23:42Z $ ++ */ ++#ifndef _bcmcdc_h_ ++#define _bcmcdc_h_ ++#include ++ ++typedef struct cdc_ioctl { ++ uint32 cmd; /* ioctl command value */ ++ uint32 len; /* lower 16: output buflen; upper 16: input buflen (excludes header) */ ++ uint32 flags; /* flag defns given below */ ++ uint32 status; /* status code returned from the device */ ++} cdc_ioctl_t; ++ ++/* Max valid buffer size that can be sent to the dongle */ ++#define CDC_MAX_MSG_SIZE ETHER_MAX_LEN ++ ++/* len field is divided into input and output buffer lengths */ ++#define CDCL_IOC_OUTLEN_MASK 0x0000FFFF /* maximum or expected response length, */ ++ /* excluding IOCTL header */ ++#define CDCL_IOC_OUTLEN_SHIFT 0 ++#define CDCL_IOC_INLEN_MASK 0xFFFF0000 /* input buffer length, excluding IOCTL header */ ++#define CDCL_IOC_INLEN_SHIFT 16 ++ ++/* CDC flag definitions */ ++#define CDCF_IOC_ERROR 0x01 /* 0=success, 1=ioctl cmd failed */ ++#define CDCF_IOC_SET 0x02 /* 0=get, 1=set cmd */ ++#define CDCF_IOC_OVL_IDX_MASK 0x3c /* overlay region index mask */ ++#define CDCF_IOC_OVL_RSV 0x40 /* 1=reserve this overlay region */ ++#define CDCF_IOC_OVL 0x80 /* 1=this ioctl corresponds to an overlay */ ++#define CDCF_IOC_ACTION_MASK 0xfe /* SET/GET, OVL_IDX, OVL_RSV, OVL mask */ ++#define CDCF_IOC_ACTION_SHIFT 1 /* SET/GET, OVL_IDX, OVL_RSV, OVL shift */ ++#define CDCF_IOC_IF_MASK 0xF000 /* I/F index */ ++#define CDCF_IOC_IF_SHIFT 12 ++#define CDCF_IOC_ID_MASK 0xFFFF0000 /* used to uniquely id an ioctl req/resp pairing */ ++#define CDCF_IOC_ID_SHIFT 16 /* # of bits of shift for ID Mask */ ++ ++#define CDC_IOC_IF_IDX(flags) (((flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT) ++#define CDC_IOC_ID(flags) (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT) ++ ++#define CDC_GET_IF_IDX(hdr) \ ++ ((int)((((hdr)->flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT)) ++#define CDC_SET_IF_IDX(hdr, idx) \ ++ ((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | ((idx) << CDCF_IOC_IF_SHIFT))) ++ ++/* ++ * BDC header ++ * ++ * The BDC header is used on data packets to convey priority across USB. ++ */ ++ ++struct bdc_header { ++ uint8 flags; /* Flags */ ++ uint8 priority; /* 802.1d Priority 0:2 bits, 4:7 USB flow control info */ ++ uint8 flags2; ++ uint8 dataOffset; /* Offset from end of BDC header to packet data, in ++ * 4-byte words. Leaves room for optional headers. ++ */ ++}; ++ ++#define BDC_HEADER_LEN 4 ++ ++/* flags field bitmap */ ++#define BDC_FLAG_80211_PKT 0x01 /* Packet is in 802.11 format (dongle -> host) */ ++#define BDC_FLAG_SUM_GOOD 0x04 /* Dongle has verified good RX checksums */ ++#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums: host->device */ ++#define BDC_FLAG_EVENT_MSG 0x08 /* Payload contains an event msg: device->host */ ++#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ ++#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ ++ ++/* priority field bitmap */ ++#define BDC_PRIORITY_MASK 0x07 ++#define BDC_PRIORITY_FC_MASK 0xf0 /* flow control info mask */ ++#define BDC_PRIORITY_FC_SHIFT 4 /* flow control info shift */ ++ ++/* flags2 field bitmap */ ++#define BDC_FLAG2_IF_MASK 0x0f /* interface index (host <-> dongle) */ ++#define BDC_FLAG2_IF_SHIFT 0 ++#define BDC_FLAG2_FC_FLAG 0x10 /* flag to indicate if pkt contains */ ++ /* FLOW CONTROL info only */ ++ ++/* version numbers */ ++#define BDC_PROTO_VER_1 1 /* Old Protocol version */ ++#define BDC_PROTO_VER 2 /* Protocol version */ ++ ++/* flags2.if field access macros */ ++#define BDC_GET_IF_IDX(hdr) \ ++ ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT)) ++#define BDC_SET_IF_IDX(hdr, idx) \ ++ ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | ((idx) << BDC_FLAG2_IF_SHIFT))) ++ ++#define BDC_FLAG2_PAD_MASK 0xf0 ++#define BDC_FLAG_PAD_MASK 0x03 ++#define BDC_FLAG2_PAD_SHIFT 2 ++#define BDC_FLAG_PAD_SHIFT 0 ++#define BDC_FLAG2_PAD_IDX 0x3c ++#define BDC_FLAG_PAD_IDX 0x03 ++#define BDC_GET_PAD_LEN(hdr) \ ++ ((int)(((((hdr)->flags2) & BDC_FLAG2_PAD_MASK) >> BDC_FLAG2_PAD_SHIFT) | \ ++ ((((hdr)->flags) & BDC_FLAG_PAD_MASK) >> BDC_FLAG_PAD_SHIFT))) ++#define BDC_SET_PAD_LEN(hdr, idx) \ ++ ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_PAD_MASK) | \ ++ (((idx) & BDC_FLAG2_PAD_IDX) << BDC_FLAG2_PAD_SHIFT))); \ ++ ((hdr)->flags = (((hdr)->flags & ~BDC_FLAG_PAD_MASK) | \ ++ (((idx) & BDC_FLAG_PAD_IDX) << BDC_FLAG_PAD_SHIFT))) ++ ++#endif /* _bcmcdc_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmdefs.h b/drivers/net/wireless/ap6211/include/bcmdefs.h +new file mode 100755 +index 0000000..00906e3 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmdefs.h +@@ -0,0 +1,270 @@ ++/* ++ * Misc system wide definitions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmdefs.h 316830 2012-02-23 20:29:22Z $ ++ */ ++ ++#ifndef _bcmdefs_h_ ++#define _bcmdefs_h_ ++ ++/* ++ * One doesn't need to include this file explicitly, gets included automatically if ++ * typedefs.h is included. ++ */ ++ ++/* Use BCM_REFERENCE to suppress warnings about intentionally-unused function ++ * arguments or local variables. ++ */ ++#define BCM_REFERENCE(data) ((void)(data)) ++ ++/* Compile-time assert can be used in place of ASSERT if the expression evaluates ++ * to a constant at compile time. ++ */ ++#define STATIC_ASSERT(expr) { \ ++ /* Make sure the expression is constant. */ \ ++ typedef enum { _STATIC_ASSERT_NOT_CONSTANT = (expr) } _static_assert_e; \ ++ /* Make sure the expression is true. */ \ ++ typedef char STATIC_ASSERT_FAIL[(expr) ? 1 : -1]; \ ++} ++ ++/* Reclaiming text and data : ++ * The following macros specify special linker sections that can be reclaimed ++ * after a system is considered 'up'. ++ * BCMATTACHFN is also used for detach functions (it's not worth having a BCMDETACHFN, ++ * as in most cases, the attach function calls the detach function to clean up on error). ++ */ ++ ++#define bcmreclaimed 0 ++#define _data _data ++#define _fn _fn ++#define BCMPREATTACHDATA(_data) _data ++#define BCMPREATTACHFN(_fn) _fn ++#define _data _data ++#define _fn _fn ++#define _fn _fn ++#define BCMNMIATTACHFN(_fn) _fn ++#define BCMNMIATTACHDATA(_data) _data ++#define CONST const ++#ifndef BCMFASTPATH ++#define BCMFASTPATH ++#define BCMFASTPATH_HOST ++#endif /* BCMFASTPATH */ ++ ++ ++/* Put some library data/code into ROM to reduce RAM requirements */ ++#define _data _data ++#define BCMROMDAT_NAME(_data) _data ++#define _fn _fn ++#define _fn _fn ++#define STATIC static ++#define BCMROMDAT_ARYSIZ(data) ARRAYSIZE(data) ++#define BCMROMDAT_SIZEOF(data) sizeof(data) ++#define BCMROMDAT_APATCH(data) ++#define BCMROMDAT_SPATCH(data) ++ ++/* Bus types */ ++#define SI_BUS 0 /* SOC Interconnect */ ++#define PCI_BUS 1 /* PCI target */ ++#define PCMCIA_BUS 2 /* PCMCIA target */ ++#define SDIO_BUS 3 /* SDIO target */ ++#define JTAG_BUS 4 /* JTAG */ ++#define USB_BUS 5 /* USB (does not support R/W REG) */ ++#define SPI_BUS 6 /* gSPI target */ ++#define RPC_BUS 7 /* RPC target */ ++ ++/* Allows size optimization for single-bus image */ ++#ifdef BCMBUSTYPE ++#define BUSTYPE(bus) (BCMBUSTYPE) ++#else ++#define BUSTYPE(bus) (bus) ++#endif ++ ++/* Allows size optimization for single-backplane image */ ++#ifdef BCMCHIPTYPE ++#define CHIPTYPE(bus) (BCMCHIPTYPE) ++#else ++#define CHIPTYPE(bus) (bus) ++#endif ++ ++ ++/* Allows size optimization for SPROM support */ ++#if defined(BCMSPROMBUS) ++#define SPROMBUS (BCMSPROMBUS) ++#elif defined(SI_PCMCIA_SROM) ++#define SPROMBUS (PCMCIA_BUS) ++#else ++#define SPROMBUS (PCI_BUS) ++#endif ++ ++/* Allows size optimization for single-chip image */ ++#ifdef BCMCHIPID ++#define CHIPID(chip) (BCMCHIPID) ++#else ++#define CHIPID(chip) (chip) ++#endif ++ ++#ifdef BCMCHIPREV ++#define CHIPREV(rev) (BCMCHIPREV) ++#else ++#define CHIPREV(rev) (rev) ++#endif ++ ++/* Defines for DMA Address Width - Shared between OSL and HNDDMA */ ++#define DMADDR_MASK_32 0x0 /* Address mask for 32-bits */ ++#define DMADDR_MASK_30 0xc0000000 /* Address mask for 30-bits */ ++#define DMADDR_MASK_0 0xffffffff /* Address mask for 0-bits (hi-part) */ ++ ++#define DMADDRWIDTH_30 30 /* 30-bit addressing capability */ ++#define DMADDRWIDTH_32 32 /* 32-bit addressing capability */ ++#define DMADDRWIDTH_63 63 /* 64-bit addressing capability */ ++#define DMADDRWIDTH_64 64 /* 64-bit addressing capability */ ++ ++#ifdef BCMDMA64OSL ++typedef struct { ++ uint32 loaddr; ++ uint32 hiaddr; ++} dma64addr_t; ++ ++typedef dma64addr_t dmaaddr_t; ++#define PHYSADDRHI(_pa) ((_pa).hiaddr) ++#define PHYSADDRHISET(_pa, _val) \ ++ do { \ ++ (_pa).hiaddr = (_val); \ ++ } while (0) ++#define PHYSADDRLO(_pa) ((_pa).loaddr) ++#define PHYSADDRLOSET(_pa, _val) \ ++ do { \ ++ (_pa).loaddr = (_val); \ ++ } while (0) ++ ++#else ++typedef unsigned long dmaaddr_t; ++#define PHYSADDRHI(_pa) (0) ++#define PHYSADDRHISET(_pa, _val) ++#define PHYSADDRLO(_pa) ((_pa)) ++#define PHYSADDRLOSET(_pa, _val) \ ++ do { \ ++ (_pa) = (_val); \ ++ } while (0) ++#endif /* BCMDMA64OSL */ ++ ++/* One physical DMA segment */ ++typedef struct { ++ dmaaddr_t addr; ++ uint32 length; ++} hnddma_seg_t; ++ ++#define MAX_DMA_SEGS 4 ++ ++ ++typedef struct { ++ void *oshdmah; /* Opaque handle for OSL to store its information */ ++ uint origsize; /* Size of the virtual packet */ ++ uint nsegs; ++ hnddma_seg_t segs[MAX_DMA_SEGS]; ++} hnddma_seg_map_t; ++ ++ ++/* packet headroom necessary to accommodate the largest header in the system, (i.e TXOFF). ++ * By doing, we avoid the need to allocate an extra buffer for the header when bridging to WL. ++ * There is a compile time check in wlc.c which ensure that this value is at least as big ++ * as TXOFF. This value is used in dma_rxfill (hnddma.c). ++ */ ++ ++#if defined(BCM_RPC_NOCOPY) || defined(BCM_RCP_TXNOCOPY) ++/* add 40 bytes to allow for extra RPC header and info */ ++#define BCMEXTRAHDROOM 220 ++#else /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ ++#define BCMEXTRAHDROOM 172 ++#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ ++ ++/* Packet alignment for most efficient SDIO (can change based on platform) */ ++#ifndef SDALIGN ++#define SDALIGN 32 ++#endif ++ ++/* Headroom required for dongle-to-host communication. Packets allocated ++ * locally in the dongle (e.g. for CDC ioctls or RNDIS messages) should ++ * leave this much room in front for low-level message headers which may ++ * be needed to get across the dongle bus to the host. (These messages ++ * don't go over the network, so room for the full WL header above would ++ * be a waste.). ++*/ ++#define BCMDONGLEHDRSZ 12 ++#define BCMDONGLEPADSZ 16 ++ ++#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ) ++ ++ ++#if defined(NO_BCMDBG_ASSERT) ++# undef BCMDBG_ASSERT ++# undef BCMASSERT_LOG ++#endif ++ ++#if defined(BCMASSERT_LOG) ++#define BCMASSERT_SUPPORT ++#endif ++ ++/* Macros for doing definition and get/set of bitfields ++ * Usage example, e.g. a three-bit field (bits 4-6): ++ * #define _M BITFIELD_MASK(3) ++ * #define _S 4 ++ * ... ++ * regval = R_REG(osh, ®s->regfoo); ++ * field = GFIELD(regval, ); ++ * regval = SFIELD(regval, , 1); ++ * W_REG(osh, ®s->regfoo, regval); ++ */ ++#define BITFIELD_MASK(width) \ ++ (((unsigned)1 << (width)) - 1) ++#define GFIELD(val, field) \ ++ (((val) >> field ## _S) & field ## _M) ++#define SFIELD(val, field, bits) \ ++ (((val) & (~(field ## _M << field ## _S))) | \ ++ ((unsigned)(bits) << field ## _S)) ++ ++/* define BCMSMALL to remove misc features for memory-constrained environments */ ++#ifdef BCMSMALL ++#undef BCMSPACE ++#define bcmspace FALSE /* if (bcmspace) code is discarded */ ++#else ++#define BCMSPACE ++#define bcmspace TRUE /* if (bcmspace) code is retained */ ++#endif ++ ++/* Max. nvram variable table size */ ++#define MAXSZ_NVRAM_VARS 4096 ++ ++ ++/* Max size for reclaimable NVRAM array */ ++#ifdef DL_NVRAM ++#define NVRAM_ARRAY_MAXSIZE DL_NVRAM ++#else ++#define NVRAM_ARRAY_MAXSIZE MAXSZ_NVRAM_VARS ++#endif /* DL_NVRAM */ ++ ++#ifdef BCMUSBDEV_ENABLED ++extern uint32 gFWID; ++#endif ++ ++#endif /* _bcmdefs_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmdevs.h b/drivers/net/wireless/ap6211/include/bcmdevs.h +new file mode 100755 +index 0000000..c3dd89f +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmdevs.h +@@ -0,0 +1,503 @@ ++/* ++ * Broadcom device-specific manifest constants. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmdevs.h 329854 2012-04-27 01:42:28Z $ ++ */ ++ ++#ifndef _BCMDEVS_H ++#define _BCMDEVS_H ++ ++/* PCI vendor IDs */ ++#define VENDOR_EPIGRAM 0xfeda ++#define VENDOR_BROADCOM 0x14e4 ++#define VENDOR_3COM 0x10b7 ++#define VENDOR_NETGEAR 0x1385 ++#define VENDOR_DIAMOND 0x1092 ++#define VENDOR_INTEL 0x8086 ++#define VENDOR_DELL 0x1028 ++#define VENDOR_HP 0x103c ++#define VENDOR_HP_COMPAQ 0x0e11 ++#define VENDOR_APPLE 0x106b ++#define VENDOR_SI_IMAGE 0x1095 /* Silicon Image, used by Arasan SDIO Host */ ++#define VENDOR_BUFFALO 0x1154 /* Buffalo vendor id */ ++#define VENDOR_TI 0x104c /* Texas Instruments */ ++#define VENDOR_RICOH 0x1180 /* Ricoh */ ++#define VENDOR_JMICRON 0x197b ++ ++ ++/* PCMCIA vendor IDs */ ++#define VENDOR_BROADCOM_PCMCIA 0x02d0 ++ ++/* SDIO vendor IDs */ ++#define VENDOR_BROADCOM_SDIO 0x00BF ++ ++/* DONGLE VID/PIDs */ ++#define BCM_DNGL_VID 0x0a5c ++#define BCM_DNGL_BL_PID_4328 0xbd12 ++#define BCM_DNGL_BL_PID_4322 0xbd13 ++#define BCM_DNGL_BL_PID_4319 0xbd16 ++#define BCM_DNGL_BL_PID_43236 0xbd17 ++#define BCM_DNGL_BL_PID_4332 0xbd18 ++#define BCM_DNGL_BL_PID_4330 0xbd19 ++#define BCM_DNGL_BL_PID_4334 0xbd1a ++#define BCM_DNGL_BL_PID_43239 0xbd1b ++#define BCM_DNGL_BL_PID_4324 0xbd1c ++#define BCM_DNGL_BL_PID_4360 0xbd1d ++ ++#define BCM_DNGL_BDC_PID 0x0bdc ++#define BCM_DNGL_JTAG_PID 0x4a44 ++ ++/* HW USB BLOCK [CPULESS USB] PIDs */ ++#define BCM_HWUSB_PID_43239 43239 ++ ++/* PCI Device IDs */ ++#define BCM4210_DEVICE_ID 0x1072 /* never used */ ++#define BCM4230_DEVICE_ID 0x1086 /* never used */ ++#define BCM4401_ENET_ID 0x170c /* 4401b0 production enet cards */ ++#define BCM3352_DEVICE_ID 0x3352 /* bcm3352 device id */ ++#define BCM3360_DEVICE_ID 0x3360 /* bcm3360 device id */ ++#define BCM4211_DEVICE_ID 0x4211 ++#define BCM4231_DEVICE_ID 0x4231 ++#define BCM4303_D11B_ID 0x4303 /* 4303 802.11b */ ++#define BCM4311_D11G_ID 0x4311 /* 4311 802.11b/g id */ ++#define BCM4311_D11DUAL_ID 0x4312 /* 4311 802.11a/b/g id */ ++#define BCM4311_D11A_ID 0x4313 /* 4311 802.11a id */ ++#define BCM4328_D11DUAL_ID 0x4314 /* 4328/4312 802.11a/g id */ ++#define BCM4328_D11G_ID 0x4315 /* 4328/4312 802.11g id */ ++#define BCM4328_D11A_ID 0x4316 /* 4328/4312 802.11a id */ ++#define BCM4318_D11G_ID 0x4318 /* 4318 802.11b/g id */ ++#define BCM4318_D11DUAL_ID 0x4319 /* 4318 802.11a/b/g id */ ++#define BCM4318_D11A_ID 0x431a /* 4318 802.11a id */ ++#define BCM4325_D11DUAL_ID 0x431b /* 4325 802.11a/g id */ ++#define BCM4325_D11G_ID 0x431c /* 4325 802.11g id */ ++#define BCM4325_D11A_ID 0x431d /* 4325 802.11a id */ ++#define BCM4306_D11G_ID 0x4320 /* 4306 802.11g */ ++#define BCM4306_D11A_ID 0x4321 /* 4306 802.11a */ ++#define BCM4306_UART_ID 0x4322 /* 4306 uart */ ++#define BCM4306_V90_ID 0x4323 /* 4306 v90 codec */ ++#define BCM4306_D11DUAL_ID 0x4324 /* 4306 dual A+B */ ++#define BCM4306_D11G_ID2 0x4325 /* BCM4306_D11G_ID; INF w/loose binding war */ ++#define BCM4321_D11N_ID 0x4328 /* 4321 802.11n dualband id */ ++#define BCM4321_D11N2G_ID 0x4329 /* 4321 802.11n 2.4Ghz band id */ ++#define BCM4321_D11N5G_ID 0x432a /* 4321 802.11n 5Ghz band id */ ++#define BCM4322_D11N_ID 0x432b /* 4322 802.11n dualband device */ ++#define BCM4322_D11N2G_ID 0x432c /* 4322 802.11n 2.4GHz device */ ++#define BCM4322_D11N5G_ID 0x432d /* 4322 802.11n 5GHz device */ ++#define BCM4329_D11N_ID 0x432e /* 4329 802.11n dualband device */ ++#define BCM4329_D11N2G_ID 0x432f /* 4329 802.11n 2.4G device */ ++#define BCM4329_D11N5G_ID 0x4330 /* 4329 802.11n 5G device */ ++#define BCM4315_D11DUAL_ID 0x4334 /* 4315 802.11a/g id */ ++#define BCM4315_D11G_ID 0x4335 /* 4315 802.11g id */ ++#define BCM4315_D11A_ID 0x4336 /* 4315 802.11a id */ ++#define BCM4319_D11N_ID 0x4337 /* 4319 802.11n dualband device */ ++#define BCM4319_D11N2G_ID 0x4338 /* 4319 802.11n 2.4G device */ ++#define BCM4319_D11N5G_ID 0x4339 /* 4319 802.11n 5G device */ ++#define BCM43231_D11N2G_ID 0x4340 /* 43231 802.11n 2.4GHz device */ ++#define BCM43221_D11N2G_ID 0x4341 /* 43221 802.11n 2.4GHz device */ ++#define BCM43222_D11N_ID 0x4350 /* 43222 802.11n dualband device */ ++#define BCM43222_D11N2G_ID 0x4351 /* 43222 802.11n 2.4GHz device */ ++#define BCM43222_D11N5G_ID 0x4352 /* 43222 802.11n 5GHz device */ ++#define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */ ++#define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db device */ ++#define BCM43226_D11N_ID 0x4354 /* 43226 802.11n dualband device */ ++#define BCM43236_D11N_ID 0x4346 /* 43236 802.11n dualband device */ ++#define BCM43236_D11N2G_ID 0x4347 /* 43236 802.11n 2.4GHz device */ ++#define BCM43236_D11N5G_ID 0x4348 /* 43236 802.11n 5GHz device */ ++#define BCM43225_D11N2G_ID 0x4357 /* 43225 802.11n 2.4GHz device */ ++#define BCM43421_D11N_ID 0xA99D /* 43421 802.11n dualband device */ ++#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ ++#define BCM4330_D11N_ID 0x4360 /* 4330 802.11n dualband device */ ++#define BCM4330_D11N2G_ID 0x4361 /* 4330 802.11n 2.4G device */ ++#define BCM4330_D11N5G_ID 0x4362 /* 4330 802.11n 5G device */ ++#define BCM4336_D11N_ID 0x4343 /* 4336 802.11n 2.4GHz device */ ++#define BCM6362_D11N_ID 0x435f /* 6362 802.11n dualband device */ ++#define BCM4331_D11N_ID 0x4331 /* 4331 802.11n dualband id */ ++#define BCM4331_D11N2G_ID 0x4332 /* 4331 802.11n 2.4Ghz band id */ ++#define BCM4331_D11N5G_ID 0x4333 /* 4331 802.11n 5Ghz band id */ ++#define BCM43237_D11N_ID 0x4355 /* 43237 802.11n dualband device */ ++#define BCM43237_D11N5G_ID 0x4356 /* 43237 802.11n 5GHz device */ ++#define BCM43227_D11N2G_ID 0x4358 /* 43228 802.11n 2.4GHz device */ ++#define BCM43228_D11N_ID 0x4359 /* 43228 802.11n DualBand device */ ++#define BCM43228_D11N5G_ID 0x435a /* 43228 802.11n 5GHz device */ ++#define BCM43362_D11N_ID 0x4363 /* 43362 802.11n 2.4GHz device */ ++#define BCM43239_D11N_ID 0x4370 /* 43239 802.11n dualband device */ ++#define BCM4324_D11N_ID 0x4374 /* 4324 802.11n dualband device */ ++#define BCM43217_D11N2G_ID 0x43a9 /* 43217 802.11n 2.4GHz device */ ++#define BCM43131_D11N2G_ID 0x43aa /* 43131 802.11n 2.4GHz device */ ++#define BCM4314_D11N2G_ID 0x4364 /* 4314 802.11n 2.4G device */ ++#define BCM43142_D11N2G_ID 0x4365 /* 43142 802.11n 2.4G device */ ++#define BCM4334_D11N_ID 0x4380 /* 4334 802.11n dualband device */ ++#define BCM4334_D11N2G_ID 0x4381 /* 4334 802.11n 2.4G device */ ++#define BCM4334_D11N5G_ID 0x4382 /* 4334 802.11n 5G device */ ++#define BCM43341_D11N_ID 0x4386 /* 43341 802.11n dualband device */ ++#define BCM43341_D11N2G_ID 0x4387 /* 43341 802.11n 2.4G device */ ++#define BCM43341_D11N5G_ID 0x4388 /* 43341 802.11n 5G device */ ++#define BCM4360_D11AC_ID 0x43a0 ++#define BCM4360_D11AC2G_ID 0x43a1 ++#define BCM4360_D11AC5G_ID 0x43a2 ++ ++/* PCI Subsystem ID */ ++#define BCM943228HMB_SSID_VEN1 0x0607 ++#define BCM94313HMGBL_SSID_VEN1 0x0608 ++#define BCM94313HMG_SSID_VEN1 0x0609 ++ ++ ++#define BCM4335_D11AC_ID 0x43ae ++#define BCM4335_D11AC2G_ID 0x43af ++#define BCM4335_D11AC5G_ID 0x43b0 ++#define BCM4352_D11AC_ID 0x43b1 /* 4352 802.11ac dualband device */ ++#define BCM4352_D11AC2G_ID 0x43b2 /* 4352 802.11ac 2.4G device */ ++#define BCM4352_D11AC5G_ID 0x43b3 /* 4352 802.11ac 5G device */ ++ ++#define BCMGPRS_UART_ID 0x4333 /* Uart id used by 4306/gprs card */ ++#define BCMGPRS2_UART_ID 0x4344 /* Uart id used by 4306/gprs card */ ++#define FPGA_JTAGM_ID 0x43f0 /* FPGA jtagm device id */ ++#define BCM_JTAGM_ID 0x43f1 /* BCM jtagm device id */ ++#define SDIOH_FPGA_ID 0x43f2 /* sdio host fpga */ ++#define BCM_SDIOH_ID 0x43f3 /* BCM sdio host id */ ++#define SDIOD_FPGA_ID 0x43f4 /* sdio device fpga */ ++#define SPIH_FPGA_ID 0x43f5 /* PCI SPI Host Controller FPGA */ ++#define BCM_SPIH_ID 0x43f6 /* Synopsis SPI Host Controller */ ++#define MIMO_FPGA_ID 0x43f8 /* FPGA mimo minimacphy device id */ ++#define BCM_JTAGM2_ID 0x43f9 /* BCM alternate jtagm device id */ ++#define SDHCI_FPGA_ID 0x43fa /* Standard SDIO Host Controller FPGA */ ++#define BCM4402_ENET_ID 0x4402 /* 4402 enet */ ++#define BCM4402_V90_ID 0x4403 /* 4402 v90 codec */ ++#define BCM4410_DEVICE_ID 0x4410 /* bcm44xx family pci iline */ ++#define BCM4412_DEVICE_ID 0x4412 /* bcm44xx family pci enet */ ++#define BCM4430_DEVICE_ID 0x4430 /* bcm44xx family cardbus iline */ ++#define BCM4432_DEVICE_ID 0x4432 /* bcm44xx family cardbus enet */ ++#define BCM4704_ENET_ID 0x4706 /* 4704 enet (Use 47XX_ENET_ID instead!) */ ++#define BCM4710_DEVICE_ID 0x4710 /* 4710 primary function 0 */ ++#define BCM47XX_AUDIO_ID 0x4711 /* 47xx audio codec */ ++#define BCM47XX_V90_ID 0x4712 /* 47xx v90 codec */ ++#define BCM47XX_ENET_ID 0x4713 /* 47xx enet */ ++#define BCM47XX_EXT_ID 0x4714 /* 47xx external i/f */ ++#define BCM47XX_GMAC_ID 0x4715 /* 47xx Unimac based GbE */ ++#define BCM47XX_USBH_ID 0x4716 /* 47xx usb host */ ++#define BCM47XX_USBD_ID 0x4717 /* 47xx usb device */ ++#define BCM47XX_IPSEC_ID 0x4718 /* 47xx ipsec */ ++#define BCM47XX_ROBO_ID 0x4719 /* 47xx/53xx roboswitch core */ ++#define BCM47XX_USB20H_ID 0x471a /* 47xx usb 2.0 host */ ++#define BCM47XX_USB20D_ID 0x471b /* 47xx usb 2.0 device */ ++#define BCM47XX_ATA100_ID 0x471d /* 47xx parallel ATA */ ++#define BCM47XX_SATAXOR_ID 0x471e /* 47xx serial ATA & XOR DMA */ ++#define BCM47XX_GIGETH_ID 0x471f /* 47xx GbE (5700) */ ++#define BCM4712_MIPS_ID 0x4720 /* 4712 base devid */ ++#define BCM4716_DEVICE_ID 0x4722 /* 4716 base devid */ ++#define BCM47XX_SMBUS_EMU_ID 0x47fe /* 47xx emulated SMBus device */ ++#define BCM47XX_XOR_EMU_ID 0x47ff /* 47xx emulated XOR engine */ ++#define EPI41210_DEVICE_ID 0xa0fa /* bcm4210 */ ++#define EPI41230_DEVICE_ID 0xa10e /* bcm4230 */ ++#define JINVANI_SDIOH_ID 0x4743 /* Jinvani SDIO Gold Host */ ++#define BCM27XX_SDIOH_ID 0x2702 /* BCM27xx Standard SDIO Host */ ++#define PCIXX21_FLASHMEDIA_ID 0x803b /* TI PCI xx21 Standard Host Controller */ ++#define PCIXX21_SDIOH_ID 0x803c /* TI PCI xx21 Standard Host Controller */ ++#define R5C822_SDIOH_ID 0x0822 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host */ ++#define JMICRON_SDIOH_ID 0x2381 /* JMicron Standard SDIO Host Controller */ ++ ++/* Chip IDs */ ++#define BCM4306_CHIP_ID 0x4306 /* 4306 chipcommon chipid */ ++#define BCM4311_CHIP_ID 0x4311 /* 4311 PCIe 802.11a/b/g */ ++#define BCM43111_CHIP_ID 43111 /* 43111 chipcommon chipid (OTP chipid) */ ++#define BCM43112_CHIP_ID 43112 /* 43112 chipcommon chipid (OTP chipid) */ ++#define BCM4312_CHIP_ID 0x4312 /* 4312 chipcommon chipid */ ++#define BCM4313_CHIP_ID 0x4313 /* 4313 chip id */ ++#define BCM43131_CHIP_ID 43131 /* 43131 chip id (OTP chipid) */ ++#define BCM4315_CHIP_ID 0x4315 /* 4315 chip id */ ++#define BCM4318_CHIP_ID 0x4318 /* 4318 chipcommon chipid */ ++#define BCM4319_CHIP_ID 0x4319 /* 4319 chip id */ ++#define BCM4320_CHIP_ID 0x4320 /* 4320 chipcommon chipid */ ++#define BCM4321_CHIP_ID 0x4321 /* 4321 chipcommon chipid */ ++#define BCM43217_CHIP_ID 43217 /* 43217 chip id (OTP chipid) */ ++#define BCM4322_CHIP_ID 0x4322 /* 4322 chipcommon chipid */ ++#define BCM43221_CHIP_ID 43221 /* 43221 chipcommon chipid (OTP chipid) */ ++#define BCM43222_CHIP_ID 43222 /* 43222 chipcommon chipid */ ++#define BCM43224_CHIP_ID 43224 /* 43224 chipcommon chipid */ ++#define BCM43225_CHIP_ID 43225 /* 43225 chipcommon chipid */ ++#define BCM43227_CHIP_ID 43227 /* 43227 chipcommon chipid */ ++#define BCM43228_CHIP_ID 43228 /* 43228 chipcommon chipid */ ++#define BCM43226_CHIP_ID 43226 /* 43226 chipcommon chipid */ ++#define BCM43231_CHIP_ID 43231 /* 43231 chipcommon chipid (OTP chipid) */ ++#define BCM43234_CHIP_ID 43234 /* 43234 chipcommon chipid */ ++#define BCM43235_CHIP_ID 43235 /* 43235 chipcommon chipid */ ++#define BCM43236_CHIP_ID 43236 /* 43236 chipcommon chipid */ ++#define BCM43237_CHIP_ID 43237 /* 43237 chipcommon chipid */ ++#define BCM43238_CHIP_ID 43238 /* 43238 chipcommon chipid */ ++#define BCM43239_CHIP_ID 43239 /* 43239 chipcommon chipid */ ++#define BCM43420_CHIP_ID 43420 /* 43222 chipcommon chipid (OTP, RBBU) */ ++#define BCM43421_CHIP_ID 43421 /* 43224 chipcommon chipid (OTP, RBBU) */ ++#define BCM43428_CHIP_ID 43428 /* 43228 chipcommon chipid (OTP, RBBU) */ ++#define BCM43431_CHIP_ID 43431 /* 4331 chipcommon chipid (OTP, RBBU) */ ++#define BCM43460_CHIP_ID 43460 /* 4360 chipcommon chipid (OTP, RBBU) */ ++#define BCM4325_CHIP_ID 0x4325 /* 4325 chip id */ ++#define BCM4328_CHIP_ID 0x4328 /* 4328 chip id */ ++#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */ ++#define BCM4331_CHIP_ID 0x4331 /* 4331 chipcommon chipid */ ++#define BCM4336_CHIP_ID 0x4336 /* 4336 chipcommon chipid */ ++#define BCM43362_CHIP_ID 43362 /* 43362 chipcommon chipid */ ++#define BCM4330_CHIP_ID 0x4330 /* 4330 chipcommon chipid */ ++#define BCM6362_CHIP_ID 0x6362 /* 6362 chipcommon chipid */ ++#define BCM4314_CHIP_ID 0x4314 /* 4314 chipcommon chipid */ ++#define BCM43142_CHIP_ID 43142 /* 43142 chipcommon chipid */ ++#define BCM4324_CHIP_ID 0x4324 /* 4324 chipcommon chipid */ ++#define BCM43242_CHIP_ID 43242 /* 43242 chipcommon chipid */ ++#define BCM4334_CHIP_ID 0x4334 /* 4334 chipcommon chipid */ ++#define BCM4360_CHIP_ID 0x4360 /* 4360 chipcommon chipid */ ++#define BCM4352_CHIP_ID 0x4352 /* 4352 chipcommon chipid */ ++#define BCM43526_CHIP_ID 0xAA06 ++#define BCM43341_CHIP_ID 43341 /* 43341 chipcommon chipid */ ++#define BCM43342_CHIP_ID 43342 /* 43342 chipcommon chipid */ ++ ++#define BCM4335_CHIP_ID 0x4335 ++ ++#define BCM4342_CHIP_ID 4342 /* 4342 chipcommon chipid (OTP, RBBU) */ ++#define BCM4402_CHIP_ID 0x4402 /* 4402 chipid */ ++#define BCM4704_CHIP_ID 0x4704 /* 4704 chipcommon chipid */ ++#define BCM4706_CHIP_ID 0x5300 /* 4706 chipcommon chipid */ ++#define BCM4710_CHIP_ID 0x4710 /* 4710 chipid */ ++#define BCM4712_CHIP_ID 0x4712 /* 4712 chipcommon chipid */ ++#define BCM4716_CHIP_ID 0x4716 /* 4716 chipcommon chipid */ ++#define BCM47162_CHIP_ID 47162 /* 47162 chipcommon chipid */ ++#define BCM4748_CHIP_ID 0x4748 /* 4716 chipcommon chipid (OTP, RBBU) */ ++#define BCM4749_CHIP_ID 0x4749 /* 5357 chipcommon chipid (OTP, RBBU) */ ++#define BCM4785_CHIP_ID 0x4785 /* 4785 chipcommon chipid */ ++#define BCM5350_CHIP_ID 0x5350 /* 5350 chipcommon chipid */ ++#define BCM5352_CHIP_ID 0x5352 /* 5352 chipcommon chipid */ ++#define BCM5354_CHIP_ID 0x5354 /* 5354 chipcommon chipid */ ++#define BCM5365_CHIP_ID 0x5365 /* 5365 chipcommon chipid */ ++#define BCM5356_CHIP_ID 0x5356 /* 5356 chipcommon chipid */ ++#define BCM5357_CHIP_ID 0x5357 /* 5357 chipcommon chipid */ ++#define BCM53572_CHIP_ID 53572 /* 53572 chipcommon chipid */ ++ ++/* Package IDs */ ++#define BCM4303_PKG_ID 2 /* 4303 package id */ ++#define BCM4309_PKG_ID 1 /* 4309 package id */ ++#define BCM4712LARGE_PKG_ID 0 /* 340pin 4712 package id */ ++#define BCM4712SMALL_PKG_ID 1 /* 200pin 4712 package id */ ++#define BCM4712MID_PKG_ID 2 /* 225pin 4712 package id */ ++#define BCM4328USBD11G_PKG_ID 2 /* 4328 802.11g USB package id */ ++#define BCM4328USBDUAL_PKG_ID 3 /* 4328 802.11a/g USB package id */ ++#define BCM4328SDIOD11G_PKG_ID 4 /* 4328 802.11g SDIO package id */ ++#define BCM4328SDIODUAL_PKG_ID 5 /* 4328 802.11a/g SDIO package id */ ++#define BCM4329_289PIN_PKG_ID 0 /* 4329 289-pin package id */ ++#define BCM4329_182PIN_PKG_ID 1 /* 4329N 182-pin package id */ ++#define BCM5354E_PKG_ID 1 /* 5354E package id */ ++#define BCM4716_PKG_ID 8 /* 4716 package id */ ++#define BCM4717_PKG_ID 9 /* 4717 package id */ ++#define BCM4718_PKG_ID 10 /* 4718 package id */ ++#define BCM5356_PKG_NONMODE 1 /* 5356 package without nmode suppport */ ++#define BCM5358U_PKG_ID 8 /* 5358U package id */ ++#define BCM5358_PKG_ID 9 /* 5358 package id */ ++#define BCM47186_PKG_ID 10 /* 47186 package id */ ++#define BCM5357_PKG_ID 11 /* 5357 package id */ ++#define BCM5356U_PKG_ID 12 /* 5356U package id */ ++#define BCM53572_PKG_ID 8 /* 53572 package id */ ++#define BCM5357C0_PKG_ID 8 /* 5357c0 package id (the same as 53572) */ ++#define BCM47188_PKG_ID 9 /* 47188 package id */ ++#define BCM5358C0_PKG_ID 0xa /* 5358c0 package id */ ++#define BCM5356C0_PKG_ID 0xb /* 5356c0 package id */ ++#define BCM4331TT_PKG_ID 8 /* 4331 12x12 package id */ ++#define BCM4331TN_PKG_ID 9 /* 4331 12x9 package id */ ++#define BCM4331TNA0_PKG_ID 0xb /* 4331 12x9 package id */ ++#define BCM4706L_PKG_ID 1 /* 4706L package id */ ++ ++#define HDLSIM5350_PKG_ID 1 /* HDL simulator package id for a 5350 */ ++#define HDLSIM_PKG_ID 14 /* HDL simulator package id */ ++#define HWSIM_PKG_ID 15 /* Hardware simulator package id */ ++#define BCM43224_FAB_CSM 0x8 /* the chip is manufactured by CSM */ ++#define BCM43224_FAB_SMIC 0xa /* the chip is manufactured by SMIC */ ++#define BCM4336_WLBGA_PKG_ID 0x8 ++#define BCM4330_WLBGA_PKG_ID 0x0 ++#define BCM4314PCIE_ARM_PKG_ID (8 | 0) /* 4314 QFN PCI package id, bit 3 tie high */ ++#define BCM4314SDIO_PKG_ID (8 | 1) /* 4314 QFN SDIO package id */ ++#define BCM4314PCIE_PKG_ID (8 | 2) /* 4314 QFN PCI (ARM-less) package id */ ++#define BCM4314SDIO_ARM_PKG_ID (8 | 3) /* 4314 QFN SDIO (ARM-less) package id */ ++#define BCM4314SDIO_FPBGA_PKG_ID (8 | 4) /* 4314 FpBGA SDIO package id */ ++#define BCM4314DEV_PKG_ID (8 | 6) /* 4314 Developement package id */ ++ ++#define PCIXX21_FLASHMEDIA0_ID 0x8033 /* TI PCI xx21 Standard Host Controller */ ++#define PCIXX21_SDIOH0_ID 0x8034 /* TI PCI xx21 Standard Host Controller */ ++ ++/* boardflags */ ++#define BFL_BTC2WIRE 0x00000001 /* old 2wire Bluetooth coexistence, OBSOLETE */ ++#define BFL_BTCOEX 0x00000001 /* Board supports BTCOEX */ ++#define BFL_PACTRL 0x00000002 /* Board has gpio 9 controlling the PA */ ++#define BFL_AIRLINEMODE 0x00000004 /* Board implements gpio 13 radio disable indication, UNUSED */ ++#define BFL_ADCDIV 0x00000008 /* Board has the rssi ADC divider */ ++#define BFL_RFPLL 0x00000008 /* ACPHY: Changing RFPLL BW to be 150 MHz */ ++#define BFL_ENETROBO 0x00000010 /* Board has robo switch or core */ ++#define BFL_NOPLLDOWN 0x00000020 /* Not ok to power down the chip pll and oscillator */ ++#define BFL_CCKHIPWR 0x00000040 /* Can do high-power CCK transmission */ ++#define BFL_ENETADM 0x00000080 /* Board has ADMtek switch */ ++#define BFL_ENETVLAN 0x00000100 /* Board has VLAN capability */ ++#define BFL_UNUSED 0x00000200 ++#define BFL_NOPCI 0x00000400 /* Board leaves PCI floating */ ++#define BFL_FEM 0x00000800 /* Board supports the Front End Module */ ++#define BFL_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */ ++#define BFL_HGPA 0x00002000 /* Board has a high gain PA */ ++#define BFL_BTC2WIRE_ALTGPIO 0x00004000 /* Board's BTC 2wire is in the alternate gpios */ ++#define BFL_ALTIQ 0x00008000 /* Alternate I/Q settings */ ++#define BFL_NOPA 0x00010000 /* Board has no PA */ ++#define BFL_RSSIINV 0x00020000 /* Board's RSSI uses positive slope(not TSSI) */ ++#define BFL_PAREF 0x00040000 /* Board uses the PARef LDO */ ++#define BFL_3TSWITCH 0x00080000 /* Board uses a triple throw switch shared with BT */ ++#define BFL_PHASESHIFT 0x00100000 /* Board can support phase shifter */ ++#define BFL_BUCKBOOST 0x00200000 /* Power topology uses BUCKBOOST */ ++#define BFL_FEM_BT 0x00400000 /* Board has FEM and switch to share antenna w/ BT */ ++#define BFL_NOCBUCK 0x00800000 /* Power topology doesn't use CBUCK */ ++#define BFL_CCKFAVOREVM 0x01000000 /* Favor CCK EVM over spectral mask */ ++#define BFL_PALDO 0x02000000 /* Power topology uses PALDO */ ++#define BFL_LNLDO2_2P5 0x04000000 /* Select 2.5V as LNLDO2 output voltage */ ++#define BFL_FASTPWR 0x08000000 ++#define BFL_UCPWRCTL_MININDX 0x08000000 /* Enforce min power index to avoid FEM damage */ ++#define BFL_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */ ++#define BFL_TRSW_1by2 0x20000000 /* Board has 2 TRSW's in 1by2 designs */ ++#define BFL_LO_TRSW_R_5GHz 0x40000000 /* In 5G do not throw TRSW to T for clipLO gain */ ++#define BFL_ELNA_GAINDEF 0x80000000 /* Backoff InitGain based on elna_2g/5g field ++ * when this flag is set ++ */ ++#define BFL_EXTLNA_TX 0x20000000 /* Temp boardflag to indicate to */ ++ ++/* boardflags2 */ ++#define BFL2_RXBB_INT_REG_DIS 0x00000001 /* Board has an external rxbb regulator */ ++#define BFL2_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */ ++#define BFL2_TXPWRCTRL_EN 0x00000004 /* Board permits enabling TX Power Control */ ++#define BFL2_2X4_DIV 0x00000008 /* Board supports the 2X4 diversity switch */ ++#define BFL2_5G_PWRGAIN 0x00000010 /* Board supports 5G band power gain */ ++#define BFL2_PCIEWAR_OVR 0x00000020 /* Board overrides ASPM and Clkreq settings */ ++#define BFL2_CAESERS_BRD 0x00000040 /* Board is Caesers brd (unused by sw) */ ++#define BFL2_BTC3WIRE 0x00000080 /* Board support legacy 3 wire or 4 wire */ ++#define BFL2_BTCLEGACY 0x00000080 /* Board support legacy 3/4 wire, to replace ++ * BFL2_BTC3WIRE ++ */ ++#define BFL2_SKWRKFEM_BRD 0x00000100 /* 4321mcm93 board uses Skyworks FEM */ ++#define BFL2_SPUR_WAR 0x00000200 /* Board has a WAR for clock-harmonic spurs */ ++#define BFL2_GPLL_WAR 0x00000400 /* Flag to narrow G-band PLL loop b/w */ ++#define BFL2_TRISTATE_LED 0x00000800 /* Tri-state the LED */ ++#define BFL2_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */ ++#define BFL2_2G_SPUR_WAR 0x00002000 /* WAR to reduce and avoid clock-harmonic spurs in 2G */ ++#define BFL2_BPHY_ALL_TXCORES 0x00004000 /* Transmit bphy frames using all tx cores */ ++#define BFL2_FCC_BANDEDGE_WAR 0x00008000 /* Activates WAR to improve FCC bandedge performance */ ++#define BFL2_GPLL_WAR2 0x00010000 /* Flag to widen G-band PLL loop b/w */ ++#define BFL2_IPALVLSHIFT_3P3 0x00020000 ++#define BFL2_INTERNDET_TXIQCAL 0x00040000 /* Use internal envelope detector for TX IQCAL */ ++#define BFL2_XTALBUFOUTEN 0x00080000 /* Keep the buffered Xtal output from radio on */ ++ /* Most drivers will turn it off without this flag */ ++ /* to save power. */ ++ ++#define BFL2_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are controlled by analog PA ctrl lines */ ++#define BFL2_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are controlled by analog PA ctrl lines */ ++#define BFL2_ELNACTRL_TRSW_2G 0x00400000 /* AZW4329: 2G gmode_elna_gain controls TR Switch */ ++#define BFL2_BT_SHARE_ANT0 0x00800000 /* share core0 antenna with BT */ ++#define BFL2_TEMPSENSE_HIGHER 0x01000000 /* The tempsense threshold can sustain higher value ++ * than programmed. The exact delta is decided by ++ * driver per chip/boardtype. This can be used ++ * when tempsense qualification happens after shipment ++ */ ++#define BFL2_BTC3WIREONLY 0x02000000 /* standard 3 wire btc only. 4 wire not supported */ ++#define BFL2_PWR_NOMINAL 0x04000000 /* 0: power reduction on, 1: no power reduction */ ++#define BFL2_EXTLNA_PWRSAVE 0x08000000 /* boardflag to enable ucode to apply power save */ ++ /* ucode control of eLNA during Tx */ ++#define BFL2_4313_RADIOREG 0x10000000 ++ /* board rework */ ++#define BFL2_SDR_EN 0x20000000 /* SDR enabled or disabled */ ++ ++/* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */ ++#define BOARD_GPIO_BTC3W_IN 0x850 /* bit 4 is RF_ACTIVE, bit 6 is STATUS, bit 11 is PRI */ ++#define BOARD_GPIO_BTC3W_OUT 0x020 /* bit 5 is TX_CONF */ ++#define BOARD_GPIO_BTCMOD_IN 0x010 /* bit 4 is the alternate BT Coexistence Input */ ++#define BOARD_GPIO_BTCMOD_OUT 0x020 /* bit 5 is the alternate BT Coexistence Out */ ++#define BOARD_GPIO_BTC_IN 0x080 /* bit 7 is BT Coexistence Input */ ++#define BOARD_GPIO_BTC_OUT 0x100 /* bit 8 is BT Coexistence Out */ ++#define BOARD_GPIO_PACTRL 0x200 /* bit 9 controls the PA on new 4306 boards */ ++#define BOARD_GPIO_12 0x1000 /* gpio 12 */ ++#define BOARD_GPIO_13 0x2000 /* gpio 13 */ ++#define BOARD_GPIO_BTC4_IN 0x0800 /* gpio 11, coex4, in */ ++#define BOARD_GPIO_BTC4_BT 0x2000 /* gpio 12, coex4, bt active */ ++#define BOARD_GPIO_BTC4_STAT 0x4000 /* gpio 14, coex4, status */ ++#define BOARD_GPIO_BTC4_WLAN 0x8000 /* gpio 15, coex4, wlan active */ ++#define BOARD_GPIO_1_WLAN_PWR 0x02 /* throttle WLAN power on X21 board */ ++#define BOARD_GPIO_3_WLAN_PWR 0x08 /* throttle WLAN power on X28 board */ ++#define BOARD_GPIO_4_WLAN_PWR 0x10 /* throttle WLAN power on X19 board */ ++ ++#define GPIO_BTC4W_OUT_4312 0x010 /* bit 4 is BT_IODISABLE */ ++#define GPIO_BTC4W_OUT_43224 0x020 /* bit 5 is BT_IODISABLE */ ++#define GPIO_BTC4W_OUT_43224_SHARED 0x0e0 /* bit 5 is BT_IODISABLE */ ++#define GPIO_BTC4W_OUT_43225 0x0e0 /* bit 5 BT_IODISABLE, bit 6 SW_BT, bit 7 SW_WL */ ++#define GPIO_BTC4W_OUT_43421 0x020 /* bit 5 is BT_IODISABLE */ ++#define GPIO_BTC4W_OUT_4313 0x060 /* bit 5 SW_BT, bit 6 SW_WL */ ++#define GPIO_BTC4W_OUT_4331_SHARED 0x010 /* GPIO 4 */ ++ ++#define PCI_CFG_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */ ++#define PCI_CFG_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */ ++#define PCI_CFG_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal power-up */ ++#define PCI_CFG_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL power-down */ ++ ++/* power control defines */ ++#define PLL_DELAY 150 /* us pll on delay */ ++#define FREF_DELAY 200 /* us fref change delay */ ++#define MIN_SLOW_CLK 32 /* us Slow clock period */ ++#define XTAL_ON_DELAY 1000 /* us crystal power-on delay */ ++ ++ ++/* 43341 Boards */ ++#define BCM943341WLABGS_SSID 0x062d ++ ++/* # of GPIO pins */ ++#define GPIO_NUMPINS 32 ++ ++/* These values are used by dhd host driver. */ ++#define RDL_RAM_BASE_4319 0x60000000 ++#define RDL_RAM_BASE_4329 0x60000000 ++#define RDL_RAM_SIZE_4319 0x48000 ++#define RDL_RAM_SIZE_4329 0x48000 ++#define RDL_RAM_SIZE_43236 0x70000 ++#define RDL_RAM_BASE_43236 0x60000000 ++#define RDL_RAM_SIZE_4328 0x60000 ++#define RDL_RAM_BASE_4328 0x80000000 ++#define RDL_RAM_SIZE_4322 0x60000 ++#define RDL_RAM_BASE_4322 0x60000000 ++ ++/* generic defs for nvram "muxenab" bits */ ++#define MUXENAB_UART 0x00000001 ++#define MUXENAB_GPIO 0x00000002 ++#define MUXENAB_ERCX 0x00000004 /* External Radio BT coex */ ++#define MUXENAB_JTAG 0x00000008 ++#define MUXENAB_HOST_WAKE 0x00000010 /* configure GPIO for SDIO host_wake */ ++#define MUXENAB_I2S_EN 0x00000020 ++#define MUXENAB_I2S_MASTER 0x00000040 ++#define MUXENAB_I2S_FULL 0x00000080 ++#define MUXENAB_SFLASH 0x00000100 ++#define MUXENAB_RFSWCTRL0 0x00000200 ++#define MUXENAB_RFSWCTRL1 0x00000400 ++#define MUXENAB_RFSWCTRL2 0x00000800 ++#define MUXENAB_SECI 0x00001000 ++#define MUXENAB_BT_LEGACY 0x00002000 ++#define MUXENAB_HOST_WAKE1 0x00004000 /* configure alternative GPIO for SDIO host_wake */ ++ ++/* Boot flags */ ++#define FLASH_KERNEL_NFLASH 0x00000001 ++#define FLASH_BOOT_NFLASH 0x00000002 ++ ++#endif /* _BCMDEVS_H */ +diff --git a/drivers/net/wireless/ap6211/include/bcmendian.h b/drivers/net/wireless/ap6211/include/bcmendian.h +new file mode 100755 +index 0000000..0cf9145 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmendian.h +@@ -0,0 +1,299 @@ ++/* ++ * Byte order utilities ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmendian.h 241182 2011-02-17 21:50:03Z $ ++ * ++ * This file by default provides proper behavior on little-endian architectures. ++ * On big-endian architectures, IL_BIGENDIAN should be defined. ++ */ ++ ++#ifndef _BCMENDIAN_H_ ++#define _BCMENDIAN_H_ ++ ++#include ++ ++/* Reverse the bytes in a 16-bit value */ ++#define BCMSWAP16(val) \ ++ ((uint16)((((uint16)(val) & (uint16)0x00ffU) << 8) | \ ++ (((uint16)(val) & (uint16)0xff00U) >> 8))) ++ ++/* Reverse the bytes in a 32-bit value */ ++#define BCMSWAP32(val) \ ++ ((uint32)((((uint32)(val) & (uint32)0x000000ffU) << 24) | \ ++ (((uint32)(val) & (uint32)0x0000ff00U) << 8) | \ ++ (((uint32)(val) & (uint32)0x00ff0000U) >> 8) | \ ++ (((uint32)(val) & (uint32)0xff000000U) >> 24))) ++ ++/* Reverse the two 16-bit halves of a 32-bit value */ ++#define BCMSWAP32BY16(val) \ ++ ((uint32)((((uint32)(val) & (uint32)0x0000ffffU) << 16) | \ ++ (((uint32)(val) & (uint32)0xffff0000U) >> 16))) ++ ++/* Byte swapping macros ++ * Host <=> Network (Big Endian) for 16- and 32-bit values ++ * Host <=> Little-Endian for 16- and 32-bit values ++ */ ++#ifndef hton16 ++#define HTON16(i) BCMSWAP16(i) ++#define hton16(i) bcmswap16(i) ++#define HTON32(i) BCMSWAP32(i) ++#define hton32(i) bcmswap32(i) ++#define NTOH16(i) BCMSWAP16(i) ++#define ntoh16(i) bcmswap16(i) ++#define NTOH32(i) BCMSWAP32(i) ++#define ntoh32(i) bcmswap32(i) ++#define LTOH16(i) (i) ++#define ltoh16(i) (i) ++#define LTOH32(i) (i) ++#define ltoh32(i) (i) ++#define HTOL16(i) (i) ++#define htol16(i) (i) ++#define HTOL32(i) (i) ++#define htol32(i) (i) ++#endif /* hton16 */ ++ ++#define ltoh16_buf(buf, i) ++#define htol16_buf(buf, i) ++ ++/* Unaligned loads and stores in host byte order */ ++#define load32_ua(a) ltoh32_ua(a) ++#define store32_ua(a, v) htol32_ua_store(v, a) ++#define load16_ua(a) ltoh16_ua(a) ++#define store16_ua(a, v) htol16_ua_store(v, a) ++ ++#define _LTOH16_UA(cp) ((cp)[0] | ((cp)[1] << 8)) ++#define _LTOH32_UA(cp) ((cp)[0] | ((cp)[1] << 8) | ((cp)[2] << 16) | ((cp)[3] << 24)) ++#define _NTOH16_UA(cp) (((cp)[0] << 8) | (cp)[1]) ++#define _NTOH32_UA(cp) (((cp)[0] << 24) | ((cp)[1] << 16) | ((cp)[2] << 8) | (cp)[3]) ++ ++#define ltoh_ua(ptr) \ ++ (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ ++ sizeof(*(ptr)) == sizeof(uint16) ? _LTOH16_UA((const uint8 *)(ptr)) : \ ++ sizeof(*(ptr)) == sizeof(uint32) ? _LTOH32_UA((const uint8 *)(ptr)) : \ ++ *(uint8 *)0) ++ ++#define ntoh_ua(ptr) \ ++ (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ ++ sizeof(*(ptr)) == sizeof(uint16) ? _NTOH16_UA((const uint8 *)(ptr)) : \ ++ sizeof(*(ptr)) == sizeof(uint32) ? _NTOH32_UA((const uint8 *)(ptr)) : \ ++ *(uint8 *)0) ++ ++#ifdef __GNUC__ ++ ++/* GNU macro versions avoid referencing the argument multiple times, while also ++ * avoiding the -fno-inline used in ROM builds. ++ */ ++ ++#define bcmswap16(val) ({ \ ++ uint16 _val = (val); \ ++ BCMSWAP16(_val); \ ++}) ++ ++#define bcmswap32(val) ({ \ ++ uint32 _val = (val); \ ++ BCMSWAP32(_val); \ ++}) ++ ++#define bcmswap32by16(val) ({ \ ++ uint32 _val = (val); \ ++ BCMSWAP32BY16(_val); \ ++}) ++ ++#define bcmswap16_buf(buf, len) ({ \ ++ uint16 *_buf = (uint16 *)(buf); \ ++ uint _wds = (len) / 2; \ ++ while (_wds--) { \ ++ *_buf = bcmswap16(*_buf); \ ++ _buf++; \ ++ } \ ++}) ++ ++#define htol16_ua_store(val, bytes) ({ \ ++ uint16 _val = (val); \ ++ uint8 *_bytes = (uint8 *)(bytes); \ ++ _bytes[0] = _val & 0xff; \ ++ _bytes[1] = _val >> 8; \ ++}) ++ ++#define htol32_ua_store(val, bytes) ({ \ ++ uint32 _val = (val); \ ++ uint8 *_bytes = (uint8 *)(bytes); \ ++ _bytes[0] = _val & 0xff; \ ++ _bytes[1] = (_val >> 8) & 0xff; \ ++ _bytes[2] = (_val >> 16) & 0xff; \ ++ _bytes[3] = _val >> 24; \ ++}) ++ ++#define hton16_ua_store(val, bytes) ({ \ ++ uint16 _val = (val); \ ++ uint8 *_bytes = (uint8 *)(bytes); \ ++ _bytes[0] = _val >> 8; \ ++ _bytes[1] = _val & 0xff; \ ++}) ++ ++#define hton32_ua_store(val, bytes) ({ \ ++ uint32 _val = (val); \ ++ uint8 *_bytes = (uint8 *)(bytes); \ ++ _bytes[0] = _val >> 24; \ ++ _bytes[1] = (_val >> 16) & 0xff; \ ++ _bytes[2] = (_val >> 8) & 0xff; \ ++ _bytes[3] = _val & 0xff; \ ++}) ++ ++#define ltoh16_ua(bytes) ({ \ ++ const uint8 *_bytes = (const uint8 *)(bytes); \ ++ _LTOH16_UA(_bytes); \ ++}) ++ ++#define ltoh32_ua(bytes) ({ \ ++ const uint8 *_bytes = (const uint8 *)(bytes); \ ++ _LTOH32_UA(_bytes); \ ++}) ++ ++#define ntoh16_ua(bytes) ({ \ ++ const uint8 *_bytes = (const uint8 *)(bytes); \ ++ _NTOH16_UA(_bytes); \ ++}) ++ ++#define ntoh32_ua(bytes) ({ \ ++ const uint8 *_bytes = (const uint8 *)(bytes); \ ++ _NTOH32_UA(_bytes); \ ++}) ++ ++#else /* !__GNUC__ */ ++ ++/* Inline versions avoid referencing the argument multiple times */ ++static INLINE uint16 ++bcmswap16(uint16 val) ++{ ++ return BCMSWAP16(val); ++} ++ ++static INLINE uint32 ++bcmswap32(uint32 val) ++{ ++ return BCMSWAP32(val); ++} ++ ++static INLINE uint32 ++bcmswap32by16(uint32 val) ++{ ++ return BCMSWAP32BY16(val); ++} ++ ++/* Reverse pairs of bytes in a buffer (not for high-performance use) */ ++/* buf - start of buffer of shorts to swap */ ++/* len - byte length of buffer */ ++static INLINE void ++bcmswap16_buf(uint16 *buf, uint len) ++{ ++ len = len / 2; ++ ++ while (len--) { ++ *buf = bcmswap16(*buf); ++ buf++; ++ } ++} ++ ++/* ++ * Store 16-bit value to unaligned little-endian byte array. ++ */ ++static INLINE void ++htol16_ua_store(uint16 val, uint8 *bytes) ++{ ++ bytes[0] = val & 0xff; ++ bytes[1] = val >> 8; ++} ++ ++/* ++ * Store 32-bit value to unaligned little-endian byte array. ++ */ ++static INLINE void ++htol32_ua_store(uint32 val, uint8 *bytes) ++{ ++ bytes[0] = val & 0xff; ++ bytes[1] = (val >> 8) & 0xff; ++ bytes[2] = (val >> 16) & 0xff; ++ bytes[3] = val >> 24; ++} ++ ++/* ++ * Store 16-bit value to unaligned network-(big-)endian byte array. ++ */ ++static INLINE void ++hton16_ua_store(uint16 val, uint8 *bytes) ++{ ++ bytes[0] = val >> 8; ++ bytes[1] = val & 0xff; ++} ++ ++/* ++ * Store 32-bit value to unaligned network-(big-)endian byte array. ++ */ ++static INLINE void ++hton32_ua_store(uint32 val, uint8 *bytes) ++{ ++ bytes[0] = val >> 24; ++ bytes[1] = (val >> 16) & 0xff; ++ bytes[2] = (val >> 8) & 0xff; ++ bytes[3] = val & 0xff; ++} ++ ++/* ++ * Load 16-bit value from unaligned little-endian byte array. ++ */ ++static INLINE uint16 ++ltoh16_ua(const void *bytes) ++{ ++ return _LTOH16_UA((const uint8 *)bytes); ++} ++ ++/* ++ * Load 32-bit value from unaligned little-endian byte array. ++ */ ++static INLINE uint32 ++ltoh32_ua(const void *bytes) ++{ ++ return _LTOH32_UA((const uint8 *)bytes); ++} ++ ++/* ++ * Load 16-bit value from unaligned big-(network-)endian byte array. ++ */ ++static INLINE uint16 ++ntoh16_ua(const void *bytes) ++{ ++ return _NTOH16_UA((const uint8 *)bytes); ++} ++ ++/* ++ * Load 32-bit value from unaligned big-(network-)endian byte array. ++ */ ++static INLINE uint32 ++ntoh32_ua(const void *bytes) ++{ ++ return _NTOH32_UA((const uint8 *)bytes); ++} ++ ++#endif /* !__GNUC__ */ ++#endif /* !_BCMENDIAN_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmpcispi.h b/drivers/net/wireless/ap6211/include/bcmpcispi.h +new file mode 100755 +index 0000000..44b263c +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmpcispi.h +@@ -0,0 +1,181 @@ ++/* ++ * Broadcom PCI-SPI Host Controller Register Definitions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmpcispi.h 241182 2011-02-17 21:50:03Z $ ++ */ ++#ifndef _BCM_PCI_SPI_H ++#define _BCM_PCI_SPI_H ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif /* PAD */ ++ ++ ++typedef volatile struct { ++ uint32 spih_ctrl; /* 0x00 SPI Control Register */ ++ uint32 spih_stat; /* 0x04 SPI Status Register */ ++ uint32 spih_data; /* 0x08 SPI Data Register, 32-bits wide */ ++ uint32 spih_ext; /* 0x0C SPI Extension Register */ ++ uint32 PAD[4]; /* 0x10-0x1F PADDING */ ++ ++ uint32 spih_gpio_ctrl; /* 0x20 SPI GPIO Control Register */ ++ uint32 spih_gpio_data; /* 0x24 SPI GPIO Data Register */ ++ uint32 PAD[6]; /* 0x28-0x3F PADDING */ ++ ++ uint32 spih_int_edge; /* 0x40 SPI Interrupt Edge Register (0=Level, 1=Edge) */ ++ uint32 spih_int_pol; /* 0x44 SPI Interrupt Polarity Register (0=Active Low, */ ++ /* 1=Active High) */ ++ uint32 spih_int_mask; /* 0x48 SPI Interrupt Mask */ ++ uint32 spih_int_status; /* 0x4C SPI Interrupt Status */ ++ uint32 PAD[4]; /* 0x50-0x5F PADDING */ ++ ++ uint32 spih_hex_disp; /* 0x60 SPI 4-digit hex display value */ ++ uint32 spih_current_ma; /* 0x64 SPI SD card current consumption in mA */ ++ uint32 PAD[1]; /* 0x68 PADDING */ ++ uint32 spih_disp_sel; /* 0x6c SPI 4-digit hex display mode select (1=current) */ ++ uint32 PAD[4]; /* 0x70-0x7F PADDING */ ++ uint32 PAD[8]; /* 0x80-0x9F PADDING */ ++ uint32 PAD[8]; /* 0xA0-0xBF PADDING */ ++ uint32 spih_pll_ctrl; /* 0xC0 PLL Control Register */ ++ uint32 spih_pll_status; /* 0xC4 PLL Status Register */ ++ uint32 spih_xtal_freq; /* 0xC8 External Clock Frequency in units of 10000Hz */ ++ uint32 spih_clk_count; /* 0xCC External Clock Count Register */ ++ ++} spih_regs_t; ++ ++typedef volatile struct { ++ uint32 cfg_space[0x40]; /* 0x000-0x0FF PCI Configuration Space (Read Only) */ ++ uint32 P_IMG_CTRL0; /* 0x100 PCI Image0 Control Register */ ++ ++ uint32 P_BA0; /* 0x104 32 R/W PCI Image0 Base Address register */ ++ uint32 P_AM0; /* 0x108 32 R/W PCI Image0 Address Mask register */ ++ uint32 P_TA0; /* 0x10C 32 R/W PCI Image0 Translation Address register */ ++ uint32 P_IMG_CTRL1; /* 0x110 32 R/W PCI Image1 Control register */ ++ uint32 P_BA1; /* 0x114 32 R/W PCI Image1 Base Address register */ ++ uint32 P_AM1; /* 0x118 32 R/W PCI Image1 Address Mask register */ ++ uint32 P_TA1; /* 0x11C 32 R/W PCI Image1 Translation Address register */ ++ uint32 P_IMG_CTRL2; /* 0x120 32 R/W PCI Image2 Control register */ ++ uint32 P_BA2; /* 0x124 32 R/W PCI Image2 Base Address register */ ++ uint32 P_AM2; /* 0x128 32 R/W PCI Image2 Address Mask register */ ++ uint32 P_TA2; /* 0x12C 32 R/W PCI Image2 Translation Address register */ ++ uint32 P_IMG_CTRL3; /* 0x130 32 R/W PCI Image3 Control register */ ++ uint32 P_BA3; /* 0x134 32 R/W PCI Image3 Base Address register */ ++ uint32 P_AM3; /* 0x138 32 R/W PCI Image3 Address Mask register */ ++ uint32 P_TA3; /* 0x13C 32 R/W PCI Image3 Translation Address register */ ++ uint32 P_IMG_CTRL4; /* 0x140 32 R/W PCI Image4 Control register */ ++ uint32 P_BA4; /* 0x144 32 R/W PCI Image4 Base Address register */ ++ uint32 P_AM4; /* 0x148 32 R/W PCI Image4 Address Mask register */ ++ uint32 P_TA4; /* 0x14C 32 R/W PCI Image4 Translation Address register */ ++ uint32 P_IMG_CTRL5; /* 0x150 32 R/W PCI Image5 Control register */ ++ uint32 P_BA5; /* 0x154 32 R/W PCI Image5 Base Address register */ ++ uint32 P_AM5; /* 0x158 32 R/W PCI Image5 Address Mask register */ ++ uint32 P_TA5; /* 0x15C 32 R/W PCI Image5 Translation Address register */ ++ uint32 P_ERR_CS; /* 0x160 32 R/W PCI Error Control and Status register */ ++ uint32 P_ERR_ADDR; /* 0x164 32 R PCI Erroneous Address register */ ++ uint32 P_ERR_DATA; /* 0x168 32 R PCI Erroneous Data register */ ++ ++ uint32 PAD[5]; /* 0x16C-0x17F PADDING */ ++ ++ uint32 WB_CONF_SPC_BAR; /* 0x180 32 R WISHBONE Configuration Space Base Address */ ++ uint32 W_IMG_CTRL1; /* 0x184 32 R/W WISHBONE Image1 Control register */ ++ uint32 W_BA1; /* 0x188 32 R/W WISHBONE Image1 Base Address register */ ++ uint32 W_AM1; /* 0x18C 32 R/W WISHBONE Image1 Address Mask register */ ++ uint32 W_TA1; /* 0x190 32 R/W WISHBONE Image1 Translation Address reg */ ++ uint32 W_IMG_CTRL2; /* 0x194 32 R/W WISHBONE Image2 Control register */ ++ uint32 W_BA2; /* 0x198 32 R/W WISHBONE Image2 Base Address register */ ++ uint32 W_AM2; /* 0x19C 32 R/W WISHBONE Image2 Address Mask register */ ++ uint32 W_TA2; /* 0x1A0 32 R/W WISHBONE Image2 Translation Address reg */ ++ uint32 W_IMG_CTRL3; /* 0x1A4 32 R/W WISHBONE Image3 Control register */ ++ uint32 W_BA3; /* 0x1A8 32 R/W WISHBONE Image3 Base Address register */ ++ uint32 W_AM3; /* 0x1AC 32 R/W WISHBONE Image3 Address Mask register */ ++ uint32 W_TA3; /* 0x1B0 32 R/W WISHBONE Image3 Translation Address reg */ ++ uint32 W_IMG_CTRL4; /* 0x1B4 32 R/W WISHBONE Image4 Control register */ ++ uint32 W_BA4; /* 0x1B8 32 R/W WISHBONE Image4 Base Address register */ ++ uint32 W_AM4; /* 0x1BC 32 R/W WISHBONE Image4 Address Mask register */ ++ uint32 W_TA4; /* 0x1C0 32 R/W WISHBONE Image4 Translation Address reg */ ++ uint32 W_IMG_CTRL5; /* 0x1C4 32 R/W WISHBONE Image5 Control register */ ++ uint32 W_BA5; /* 0x1C8 32 R/W WISHBONE Image5 Base Address register */ ++ uint32 W_AM5; /* 0x1CC 32 R/W WISHBONE Image5 Address Mask register */ ++ uint32 W_TA5; /* 0x1D0 32 R/W WISHBONE Image5 Translation Address reg */ ++ uint32 W_ERR_CS; /* 0x1D4 32 R/W WISHBONE Error Control and Status reg */ ++ uint32 W_ERR_ADDR; /* 0x1D8 32 R WISHBONE Erroneous Address register */ ++ uint32 W_ERR_DATA; /* 0x1DC 32 R WISHBONE Erroneous Data register */ ++ uint32 CNF_ADDR; /* 0x1E0 32 R/W Configuration Cycle register */ ++ uint32 CNF_DATA; /* 0x1E4 32 R/W Configuration Cycle Generation Data reg */ ++ ++ uint32 INT_ACK; /* 0x1E8 32 R Interrupt Acknowledge register */ ++ uint32 ICR; /* 0x1EC 32 R/W Interrupt Control register */ ++ uint32 ISR; /* 0x1F0 32 R/W Interrupt Status register */ ++} spih_pciregs_t; ++ ++/* ++ * PCI Core interrupt enable and status bit definitions. ++ */ ++ ++/* PCI Core ICR Register bit definitions */ ++#define PCI_INT_PROP_EN (1 << 0) /* Interrupt Propagation Enable */ ++#define PCI_WB_ERR_INT_EN (1 << 1) /* Wishbone Error Interrupt Enable */ ++#define PCI_PCI_ERR_INT_EN (1 << 2) /* PCI Error Interrupt Enable */ ++#define PCI_PAR_ERR_INT_EN (1 << 3) /* Parity Error Interrupt Enable */ ++#define PCI_SYS_ERR_INT_EN (1 << 4) /* System Error Interrupt Enable */ ++#define PCI_SOFTWARE_RESET (1U << 31) /* Software reset of the PCI Core. */ ++ ++ ++/* PCI Core ISR Register bit definitions */ ++#define PCI_INT_PROP_ST (1 << 0) /* Interrupt Propagation Status */ ++#define PCI_WB_ERR_INT_ST (1 << 1) /* Wishbone Error Interrupt Status */ ++#define PCI_PCI_ERR_INT_ST (1 << 2) /* PCI Error Interrupt Status */ ++#define PCI_PAR_ERR_INT_ST (1 << 3) /* Parity Error Interrupt Status */ ++#define PCI_SYS_ERR_INT_ST (1 << 4) /* System Error Interrupt Status */ ++ ++ ++/* Registers on the Wishbone bus */ ++#define SPIH_CTLR_INTR (1 << 0) /* SPI Host Controller Core Interrupt */ ++#define SPIH_DEV_INTR (1 << 1) /* SPI Device Interrupt */ ++#define SPIH_WFIFO_INTR (1 << 2) /* SPI Tx FIFO Empty Intr (FPGA Rev >= 8) */ ++ ++/* GPIO Bit definitions */ ++#define SPIH_CS (1 << 0) /* SPI Chip Select (active low) */ ++#define SPIH_SLOT_POWER (1 << 1) /* SD Card Slot Power Enable */ ++#define SPIH_CARD_DETECT (1 << 2) /* SD Card Detect */ ++ ++/* SPI Status Register Bit definitions */ ++#define SPIH_STATE_MASK 0x30 /* SPI Transfer State Machine state mask */ ++#define SPIH_STATE_SHIFT 4 /* SPI Transfer State Machine state shift */ ++#define SPIH_WFFULL (1 << 3) /* SPI Write FIFO Full */ ++#define SPIH_WFEMPTY (1 << 2) /* SPI Write FIFO Empty */ ++#define SPIH_RFFULL (1 << 1) /* SPI Read FIFO Full */ ++#define SPIH_RFEMPTY (1 << 0) /* SPI Read FIFO Empty */ ++ ++#define SPIH_EXT_CLK (1U << 31) /* Use External Clock as PLL Clock source. */ ++ ++#define SPIH_PLL_NO_CLK (1 << 1) /* Set to 1 if the PLL's input clock is lost. */ ++#define SPIH_PLL_LOCKED (1 << 3) /* Set to 1 when the PLL is locked. */ ++ ++/* Spin bit loop bound check */ ++#define SPI_SPIN_BOUND 0xf4240 /* 1 million */ ++ ++#endif /* _BCM_PCI_SPI_H */ +diff --git a/drivers/net/wireless/ap6211/include/bcmperf.h b/drivers/net/wireless/ap6211/include/bcmperf.h +new file mode 100755 +index 0000000..7438307 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmperf.h +@@ -0,0 +1,36 @@ ++/* ++ * Performance counters software interface. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmperf.h 241182 2011-02-17 21:50:03Z $ ++ */ ++/* essai */ ++#ifndef _BCMPERF_H_ ++#define _BCMPERF_H_ ++/* get cache hits and misses */ ++#define BCMPERF_ENABLE_INSTRCOUNT() ++#define BCMPERF_ENABLE_ICACHE_MISS() ++#define BCMPERF_ENABLE_ICACHE_HIT() ++#define BCMPERF_GETICACHE_MISS(x) ((x) = 0) ++#define BCMPERF_GETICACHE_HIT(x) ((x) = 0) ++#define BCMPERF_GETINSTRCOUNT(x) ((x) = 0) ++#endif /* _BCMPERF_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmsdbus.h b/drivers/net/wireless/ap6211/include/bcmsdbus.h +new file mode 100755 +index 0000000..2fa706d +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmsdbus.h +@@ -0,0 +1,152 @@ ++/* ++ * Definitions for API from sdio common code (bcmsdh) to individual ++ * host controller drivers. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdbus.h 347614 2012-07-27 10:24:51Z $ ++ */ ++ ++#ifndef _sdio_api_h_ ++#define _sdio_api_h_ ++ ++ ++#define SDIOH_API_RC_SUCCESS (0x00) ++#define SDIOH_API_RC_FAIL (0x01) ++#define SDIOH_API_SUCCESS(status) (status == 0) ++ ++#define SDIOH_READ 0 /* Read request */ ++#define SDIOH_WRITE 1 /* Write request */ ++ ++#define SDIOH_DATA_FIX 0 /* Fixed addressing */ ++#define SDIOH_DATA_INC 1 /* Incremental addressing */ ++ ++#define SDIOH_CMD_TYPE_NORMAL 0 /* Normal command */ ++#define SDIOH_CMD_TYPE_APPEND 1 /* Append command */ ++#define SDIOH_CMD_TYPE_CUTTHRU 2 /* Cut-through command */ ++ ++#define SDIOH_DATA_PIO 0 /* PIO mode */ ++#define SDIOH_DATA_DMA 1 /* DMA mode */ ++ ++#ifdef BCMSDIOH_TXGLOM ++/* Max number of glommed pkts */ ++#define SDPCM_MAXGLOM_SIZE 10 ++#define SDPCM_DEFGLOM_SIZE 3 ++ ++#define SDPCM_TXGLOM_CPY 0 /* SDIO 2.0 should use copy mode */ ++#define SDPCM_TXGLOM_MDESC 1 /* SDIO 3.0 should use multi-desc mode */ ++#endif ++ ++ ++typedef int SDIOH_API_RC; ++ ++/* SDio Host structure */ ++typedef struct sdioh_info sdioh_info_t; ++ ++/* callback function, taking one arg */ ++typedef void (*sdioh_cb_fn_t)(void *); ++ ++/* attach, return handler on success, NULL if failed. ++ * The handler shall be provided by all subsequent calls. No local cache ++ * cfghdl points to the starting address of pci device mapped memory ++ */ ++extern sdioh_info_t * sdioh_attach(osl_t *osh, void *cfghdl, uint irq); ++extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *si); ++extern SDIOH_API_RC sdioh_interrupt_register(sdioh_info_t *si, sdioh_cb_fn_t fn, void *argh); ++extern SDIOH_API_RC sdioh_interrupt_deregister(sdioh_info_t *si); ++ ++/* query whether SD interrupt is enabled or not */ ++extern SDIOH_API_RC sdioh_interrupt_query(sdioh_info_t *si, bool *onoff); ++ ++/* enable or disable SD interrupt */ ++extern SDIOH_API_RC sdioh_interrupt_set(sdioh_info_t *si, bool enable_disable); ++ ++#if defined(DHD_DEBUG) ++extern bool sdioh_interrupt_pending(sdioh_info_t *si); ++#endif ++ ++/* read or write one byte using cmd52 */ ++extern SDIOH_API_RC sdioh_request_byte(sdioh_info_t *si, uint rw, uint fnc, uint addr, uint8 *byte); ++ ++/* read or write 2/4 bytes using cmd53 */ ++extern SDIOH_API_RC sdioh_request_word(sdioh_info_t *si, uint cmd_type, uint rw, uint fnc, ++ uint addr, uint32 *word, uint nbyte); ++ ++/* read or write any buffer using cmd53 */ ++extern SDIOH_API_RC sdioh_request_buffer(sdioh_info_t *si, uint pio_dma, uint fix_inc, ++ uint rw, uint fnc_num, uint32 addr, uint regwidth, uint32 buflen, uint8 *buffer, ++ void *pkt); ++ ++#ifdef BCMSDIOH_TXGLOM ++extern void sdioh_glom_post(sdioh_info_t *sd, uint8 *frame, uint len); ++extern void sdioh_glom_clear(sdioh_info_t *sd); ++extern uint sdioh_set_mode(sdioh_info_t *sd, uint mode); ++extern bool sdioh_glom_enabled(void); ++#else ++#define sdioh_glom_post(a, b, c) ++#define sdioh_glom_clear(a) ++#define sdioh_set_mode(a) (0) ++#define sdioh_glom_enabled() (FALSE) ++#endif ++ ++/* get cis data */ ++extern SDIOH_API_RC sdioh_cis_read(sdioh_info_t *si, uint fuc, uint8 *cis, uint32 length); ++ ++extern SDIOH_API_RC sdioh_cfg_read(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); ++extern SDIOH_API_RC sdioh_cfg_write(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); ++ ++/* query number of io functions */ ++extern uint sdioh_query_iofnum(sdioh_info_t *si); ++ ++/* handle iovars */ ++extern int sdioh_iovar_op(sdioh_info_t *si, const char *name, ++ void *params, int plen, void *arg, int len, bool set); ++ ++/* Issue abort to the specified function and clear controller as needed */ ++extern int sdioh_abort(sdioh_info_t *si, uint fnc); ++ ++/* Start and Stop SDIO without re-enumerating the SD card. */ ++extern int sdioh_start(sdioh_info_t *si, int stage); ++extern int sdioh_stop(sdioh_info_t *si); ++ ++/* Wait system lock free */ ++extern int sdioh_waitlockfree(sdioh_info_t *si); ++ ++/* Reset and re-initialize the device */ ++extern int sdioh_sdio_reset(sdioh_info_t *si); ++ ++/* Helper function */ ++void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh); ++ ++ ++ ++#if defined(BCMSDIOH_STD) ++ #define SDIOH_SLEEP_ENABLED ++#endif ++extern SDIOH_API_RC sdioh_sleep(sdioh_info_t *si, bool enab); ++ ++/* GPIO support */ ++extern SDIOH_API_RC sdioh_gpio_init(sdioh_info_t *sd); ++extern bool sdioh_gpioin(sdioh_info_t *sd, uint32 gpio); ++extern SDIOH_API_RC sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio); ++extern SDIOH_API_RC sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab); ++ ++#endif /* _sdio_api_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmsdh.h b/drivers/net/wireless/ap6211/include/bcmsdh.h +new file mode 100755 +index 0000000..8e5a563 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmsdh.h +@@ -0,0 +1,247 @@ ++/* ++ * SDIO host client driver interface of Broadcom HNBU ++ * export functions to client drivers ++ * abstract OS and BUS specific details of SDIO ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdh.h 347614 2012-07-27 10:24:51Z $ ++ */ ++ ++/** ++ * @file bcmsdh.h ++ */ ++ ++#ifndef _bcmsdh_h_ ++#define _bcmsdh_h_ ++ ++#define BCMSDH_ERROR_VAL 0x0001 /* Error */ ++#define BCMSDH_INFO_VAL 0x0002 /* Info */ ++extern const uint bcmsdh_msglevel; ++ ++#define BCMSDH_ERROR(x) ++#define BCMSDH_INFO(x) ++ ++#if (defined(BCMSDIOH_STD) || defined(BCMSDIOH_BCM) || defined(BCMSDIOH_SPI)) ++#define BCMSDH_ADAPTER ++#endif /* BCMSDIO && (BCMSDIOH_STD || BCMSDIOH_BCM || BCMSDIOH_SPI) */ ++ ++/* forward declarations */ ++typedef struct bcmsdh_info bcmsdh_info_t; ++typedef void (*bcmsdh_cb_fn_t)(void *); ++ ++/* Attach and build an interface to the underlying SD host driver. ++ * - Allocates resources (structs, arrays, mem, OS handles, etc) needed by bcmsdh. ++ * - Returns the bcmsdh handle and virtual address base for register access. ++ * The returned handle should be used in all subsequent calls, but the bcmsh ++ * implementation may maintain a single "default" handle (e.g. the first or ++ * most recent one) to enable single-instance implementations to pass NULL. ++ */ ++ ++#if 0 && (NDISVER >= 0x0630) && 1 ++extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, ++ void **regsva, uint irq, shared_info_t *sh); ++#else ++extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq); ++#endif ++ ++/* Detach - freeup resources allocated in attach */ ++extern int bcmsdh_detach(osl_t *osh, void *sdh); ++ ++/* Query if SD device interrupts are enabled */ ++extern bool bcmsdh_intr_query(void *sdh); ++ ++/* Enable/disable SD interrupt */ ++extern int bcmsdh_intr_enable(void *sdh); ++extern int bcmsdh_intr_disable(void *sdh); ++ ++/* Register/deregister device interrupt handler. */ ++extern int bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); ++extern int bcmsdh_intr_dereg(void *sdh); ++/* Enable/disable SD card interrupt forward */ ++extern void bcmsdh_intr_forward(void *sdh, bool pass); ++ ++#if defined(DHD_DEBUG) ++/* Query pending interrupt status from the host controller */ ++extern bool bcmsdh_intr_pending(void *sdh); ++#endif ++ ++/* Register a callback to be called if and when bcmsdh detects ++ * device removal. No-op in the case of non-removable/hardwired devices. ++ */ ++extern int bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); ++ ++/* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface). ++ * fn: function number ++ * addr: unmodified SDIO-space address ++ * data: data byte to write ++ * err: pointer to error code (or NULL) ++ */ ++extern uint8 bcmsdh_cfg_read(void *sdh, uint func, uint32 addr, int *err); ++extern void bcmsdh_cfg_write(void *sdh, uint func, uint32 addr, uint8 data, int *err); ++ ++/* Read/Write 4bytes from/to cfg space */ ++extern uint32 bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err); ++extern void bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err); ++ ++/* Read CIS content for specified function. ++ * fn: function whose CIS is being requested (0 is common CIS) ++ * cis: pointer to memory location to place results ++ * length: number of bytes to read ++ * Internally, this routine uses the values from the cis base regs (0x9-0xB) ++ * to form an SDIO-space address to read the data from. ++ */ ++extern int bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length); ++ ++/* Synchronous access to device (client) core registers via CMD53 to F1. ++ * addr: backplane address (i.e. >= regsva from attach) ++ * size: register width in bytes (2 or 4) ++ * data: data for register write ++ */ ++extern uint32 bcmsdh_reg_read(void *sdh, uint32 addr, uint size); ++extern uint32 bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data); ++ ++/* set sb address window */ ++extern int bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set); ++ ++/* Indicate if last reg read/write failed */ ++extern bool bcmsdh_regfail(void *sdh); ++ ++/* Buffer transfer to/from device (client) core via cmd53. ++ * fn: function number ++ * addr: backplane address (i.e. >= regsva from attach) ++ * flags: backplane width, address increment, sync/async ++ * buf: pointer to memory data buffer ++ * nbytes: number of bytes to transfer to/from buf ++ * pkt: pointer to packet associated with buf (if any) ++ * complete: callback function for command completion (async only) ++ * handle: handle for completion callback (first arg in callback) ++ * Returns 0 or error code. ++ * NOTE: Async operation is not currently supported. ++ */ ++typedef void (*bcmsdh_cmplt_fn_t)(void *handle, int status, bool sync_waiting); ++extern int bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, void *pkt, ++ bcmsdh_cmplt_fn_t complete_fn, void *handle); ++extern int bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, void *pkt, ++ bcmsdh_cmplt_fn_t complete_fn, void *handle); ++ ++extern void bcmsdh_glom_post(void *sdh, uint8 *frame, uint len); ++extern void bcmsdh_glom_clear(void *sdh); ++extern uint bcmsdh_set_mode(void *sdh, uint mode); ++extern bool bcmsdh_glom_enabled(void); ++/* Flags bits */ ++#define SDIO_REQ_4BYTE 0x1 /* Four-byte target (backplane) width (vs. two-byte) */ ++#define SDIO_REQ_FIXED 0x2 /* Fixed address (FIFO) (vs. incrementing address) */ ++#define SDIO_REQ_ASYNC 0x4 /* Async request (vs. sync request) */ ++#define SDIO_BYTE_MODE 0x8 /* Byte mode request(non-block mode) */ ++ ++/* Pending (non-error) return code */ ++#define BCME_PENDING 1 ++ ++/* Read/write to memory block (F1, no FIFO) via CMD53 (sync only). ++ * rw: read or write (0/1) ++ * addr: direct SDIO address ++ * buf: pointer to memory data buffer ++ * nbytes: number of bytes to transfer to/from buf ++ * Returns 0 or error code. ++ */ ++extern int bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes); ++ ++/* Issue an abort to the specified function */ ++extern int bcmsdh_abort(void *sdh, uint fn); ++ ++/* Start SDIO Host Controller communication */ ++extern int bcmsdh_start(void *sdh, int stage); ++ ++/* Stop SDIO Host Controller communication */ ++extern int bcmsdh_stop(void *sdh); ++ ++/* Wait system lock free */ ++extern int bcmsdh_waitlockfree(void *sdh); ++ ++/* Returns the "Device ID" of target device on the SDIO bus. */ ++extern int bcmsdh_query_device(void *sdh); ++ ++/* Returns the number of IO functions reported by the device */ ++extern uint bcmsdh_query_iofnum(void *sdh); ++ ++/* Miscellaneous knob tweaker. */ ++extern int bcmsdh_iovar_op(void *sdh, const char *name, ++ void *params, int plen, void *arg, int len, bool set); ++ ++/* Reset and reinitialize the device */ ++extern int bcmsdh_reset(bcmsdh_info_t *sdh); ++ ++/* helper functions */ ++ ++extern void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh); ++ ++/* callback functions */ ++typedef struct { ++ /* attach to device */ ++ void *(*attach)(uint16 vend_id, uint16 dev_id, uint16 bus, uint16 slot, ++ uint16 func, uint bustype, void * regsva, osl_t * osh, ++ void * param); ++ /* detach from device */ ++ void (*detach)(void *ch); ++} bcmsdh_driver_t; ++ ++/* platform specific/high level functions */ ++extern int bcmsdh_register(bcmsdh_driver_t *driver); ++extern void bcmsdh_unregister(void); ++extern bool bcmsdh_chipmatch(uint16 vendor, uint16 device); ++extern void bcmsdh_device_remove(void * sdh); ++ ++extern int bcmsdh_reg_sdio_notify(void* semaphore); ++extern void bcmsdh_unreg_sdio_notify(void); ++ ++extern int bcmsdh_set_drvdata(void * dhdp); ++ ++#if defined(OOB_INTR_ONLY) ++extern int bcmsdh_register_oob_intr(void * dhdp); ++extern void bcmsdh_unregister_oob_intr(void); ++extern void bcmsdh_oob_intr_set(bool enable); ++#endif ++#if defined(HW_OOB) ++void bcmsdh_config_hw_oob_intr(bcmsdh_info_t *sdh, uint chip); ++#endif ++ ++/* Function to pass device-status bits to DHD. */ ++extern uint32 bcmsdh_get_dstatus(void *sdh); ++ ++/* Function to return current window addr */ ++extern uint32 bcmsdh_cur_sbwad(void *sdh); ++ ++/* Function to pass chipid and rev to lower layers for controlling pr's */ ++extern void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev); ++ ++ ++extern int bcmsdh_sleep(void *sdh, bool enab); ++ ++/* GPIO support */ ++extern int bcmsdh_gpio_init(void *sd); ++extern bool bcmsdh_gpioin(void *sd, uint32 gpio); ++extern int bcmsdh_gpioouten(void *sd, uint32 gpio); ++extern int bcmsdh_gpioout(void *sd, uint32 gpio, bool enab); ++ ++#endif /* _bcmsdh_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmsdh_sdmmc.h b/drivers/net/wireless/ap6211/include/bcmsdh_sdmmc.h +new file mode 100755 +index 0000000..a169588 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmsdh_sdmmc.h +@@ -0,0 +1,109 @@ ++/* ++ * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdh_sdmmc.h 366812 2012-11-05 13:49:32Z $ ++ */ ++ ++#ifndef __BCMSDH_SDMMC_H__ ++#define __BCMSDH_SDMMC_H__ ++ ++#define sd_sync_dma(sd, read, nbytes) ++#define sd_init_dma(sd) ++#define sd_ack_intr(sd) ++#define sd_wakeup(sd); ++ ++/* Allocate/init/free per-OS private data */ ++extern int sdioh_sdmmc_osinit(sdioh_info_t *sd); ++extern void sdioh_sdmmc_osfree(sdioh_info_t *sd); ++ ++#define BLOCK_SIZE_4318 64 ++#define BLOCK_SIZE_4328 512 ++ ++/* internal return code */ ++#define SUCCESS 0 ++#define ERROR 1 ++ ++/* private bus modes */ ++#define SDIOH_MODE_SD4 2 ++#define CLIENT_INTR 0x100 /* Get rid of this! */ ++ ++struct sdioh_info { ++ osl_t *osh; /* osh handler */ ++ bool client_intr_enabled; /* interrupt connnected flag */ ++ bool intr_handler_valid; /* client driver interrupt handler valid */ ++ sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ ++ void *intr_handler_arg; /* argument to call interrupt handler */ ++ uint16 intmask; /* Current active interrupts */ ++ void *sdos_info; /* Pointer to per-OS private data */ ++ ++ uint irq; /* Client irq */ ++ int intrcount; /* Client interrupts */ ++ ++ bool sd_use_dma; /* DMA on CMD53 */ ++ bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ ++ /* Must be on for sd_multiblock to be effective */ ++ bool use_client_ints; /* If this is false, make sure to restore */ ++ int sd_mode; /* SD1/SD4/SPI */ ++ int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ ++ uint8 num_funcs; /* Supported funcs on client */ ++ uint32 com_cis_ptr; ++ uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; ++ ++#define SDIOH_SDMMC_MAX_SG_ENTRIES 32 ++ struct scatterlist sg_list[SDIOH_SDMMC_MAX_SG_ENTRIES]; ++ bool use_rxchain; ++}; ++ ++/************************************************************ ++ * Internal interfaces: per-port references into bcmsdh_sdmmc.c ++ */ ++ ++/* Global message bits */ ++extern uint sd_msglevel; ++ ++/* OS-independent interrupt handler */ ++extern bool check_client_intr(sdioh_info_t *sd); ++ ++/* Core interrupt enable/disable of device interrupts */ ++extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); ++extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); ++ ++ ++/************************************************************** ++ * Internal interfaces: bcmsdh_sdmmc.c references to per-port code ++ */ ++ ++/* Register mapping routines */ ++extern uint32 *sdioh_sdmmc_reg_map(osl_t *osh, int32 addr, int size); ++extern void sdioh_sdmmc_reg_unmap(osl_t *osh, int32 addr, int size); ++ ++/* Interrupt (de)registration routines */ ++extern int sdioh_sdmmc_register_irq(sdioh_info_t *sd, uint irq); ++extern void sdioh_sdmmc_free_irq(uint irq, sdioh_info_t *sd); ++ ++typedef struct _BCMSDH_SDMMC_INSTANCE { ++ sdioh_info_t *sd; ++ struct sdio_func *func[SDIOD_MAX_IOFUNCS]; ++} BCMSDH_SDMMC_INSTANCE, *PBCMSDH_SDMMC_INSTANCE; ++ ++#endif /* __BCMSDH_SDMMC_H__ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmsdpcm.h b/drivers/net/wireless/ap6211/include/bcmsdpcm.h +new file mode 100755 +index 0000000..fb2ec3a +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmsdpcm.h +@@ -0,0 +1,281 @@ ++/* ++ * Broadcom SDIO/PCMCIA ++ * Software-specific definitions shared between device and host side ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdpcm.h 362722 2012-10-12 23:55:55Z $ ++ */ ++ ++#ifndef _bcmsdpcm_h_ ++#define _bcmsdpcm_h_ ++ ++/* ++ * Software allocation of To SB Mailbox resources ++ */ ++ ++/* intstatus bits */ ++#define I_SMB_NAK I_SMB_SW0 /* To SB Mailbox Frame NAK */ ++#define I_SMB_INT_ACK I_SMB_SW1 /* To SB Mailbox Host Interrupt ACK */ ++#define I_SMB_USE_OOB I_SMB_SW2 /* To SB Mailbox Use OOB Wakeup */ ++#define I_SMB_DEV_INT I_SMB_SW3 /* To SB Mailbox Miscellaneous Interrupt */ ++ ++#define I_TOSBMAIL (I_SMB_NAK | I_SMB_INT_ACK | I_SMB_USE_OOB | I_SMB_DEV_INT) ++ ++/* tosbmailbox bits corresponding to intstatus bits */ ++#define SMB_NAK (1 << 0) /* To SB Mailbox Frame NAK */ ++#define SMB_INT_ACK (1 << 1) /* To SB Mailbox Host Interrupt ACK */ ++#define SMB_USE_OOB (1 << 2) /* To SB Mailbox Use OOB Wakeup */ ++#define SMB_DEV_INT (1 << 3) /* To SB Mailbox Miscellaneous Interrupt */ ++#define SMB_MASK 0x0000000f /* To SB Mailbox Mask */ ++ ++/* tosbmailboxdata */ ++#define SMB_DATA_VERSION_MASK 0x00ff0000 /* host protocol version (sent with F2 enable) */ ++#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version (sent with F2 enable) */ ++ ++/* ++ * Software allocation of To Host Mailbox resources ++ */ ++ ++/* intstatus bits */ ++#define I_HMB_FC_STATE I_HMB_SW0 /* To Host Mailbox Flow Control State */ ++#define I_HMB_FC_CHANGE I_HMB_SW1 /* To Host Mailbox Flow Control State Changed */ ++#define I_HMB_FRAME_IND I_HMB_SW2 /* To Host Mailbox Frame Indication */ ++#define I_HMB_HOST_INT I_HMB_SW3 /* To Host Mailbox Miscellaneous Interrupt */ ++ ++#define I_TOHOSTMAIL (I_HMB_FC_CHANGE | I_HMB_FRAME_IND | I_HMB_HOST_INT) ++ ++/* tohostmailbox bits corresponding to intstatus bits */ ++#define HMB_FC_ON (1 << 0) /* To Host Mailbox Flow Control State */ ++#define HMB_FC_CHANGE (1 << 1) /* To Host Mailbox Flow Control State Changed */ ++#define HMB_FRAME_IND (1 << 2) /* To Host Mailbox Frame Indication */ ++#define HMB_HOST_INT (1 << 3) /* To Host Mailbox Miscellaneous Interrupt */ ++#define HMB_MASK 0x0000000f /* To Host Mailbox Mask */ ++ ++/* tohostmailboxdata */ ++#define HMB_DATA_NAKHANDLED 0x01 /* we're ready to retransmit NAK'd frame to host */ ++#define HMB_DATA_DEVREADY 0x02 /* we're ready to to talk to host after enable */ ++#define HMB_DATA_FC 0x04 /* per prio flowcontrol update flag to host */ ++#define HMB_DATA_FWREADY 0x08 /* firmware is ready for protocol activity */ ++#define HMB_DATA_FWHALT 0x10 /* firmware has halted operation */ ++ ++#define HMB_DATA_FCDATA_MASK 0xff000000 /* per prio flowcontrol data */ ++#define HMB_DATA_FCDATA_SHIFT 24 /* per prio flowcontrol data */ ++ ++#define HMB_DATA_VERSION_MASK 0x00ff0000 /* device protocol version (with devready) */ ++#define HMB_DATA_VERSION_SHIFT 16 /* device protocol version (with devready) */ ++ ++/* ++ * Software-defined protocol header ++ */ ++ ++/* Current protocol version */ ++#define SDPCM_PROT_VERSION 4 ++ ++/* SW frame header */ ++#define SDPCM_SEQUENCE_MASK 0x000000ff /* Sequence Number Mask */ ++#define SDPCM_PACKET_SEQUENCE(p) (((uint8 *)p)[0] & 0xff) /* p starts w/SW Header */ ++ ++#define SDPCM_CHANNEL_MASK 0x00000f00 /* Channel Number Mask */ ++#define SDPCM_CHANNEL_SHIFT 8 /* Channel Number Shift */ ++#define SDPCM_PACKET_CHANNEL(p) (((uint8 *)p)[1] & 0x0f) /* p starts w/SW Header */ ++ ++#define SDPCM_FLAGS_MASK 0x0000f000 /* Mask of flag bits */ ++#define SDPCM_FLAGS_SHIFT 12 /* Flag bits shift */ ++#define SDPCM_PACKET_FLAGS(p) ((((uint8 *)p)[1] & 0xf0) >> 4) /* p starts w/SW Header */ ++ ++/* Next Read Len: lookahead length of next frame, in 16-byte units (rounded up) */ ++#define SDPCM_NEXTLEN_MASK 0x00ff0000 /* Next Read Len Mask */ ++#define SDPCM_NEXTLEN_SHIFT 16 /* Next Read Len Shift */ ++#define SDPCM_NEXTLEN_VALUE(p) ((((uint8 *)p)[2] & 0xff) << 4) /* p starts w/SW Header */ ++#define SDPCM_NEXTLEN_OFFSET 2 ++ ++/* Data Offset from SOF (HW Tag, SW Tag, Pad) */ ++#define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */ ++#define SDPCM_DOFFSET_VALUE(p) (((uint8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff) ++#define SDPCM_DOFFSET_MASK 0xff000000 ++#define SDPCM_DOFFSET_SHIFT 24 ++ ++#define SDPCM_FCMASK_OFFSET 4 /* Flow control */ ++#define SDPCM_FCMASK_VALUE(p) (((uint8 *)p)[SDPCM_FCMASK_OFFSET ] & 0xff) ++#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */ ++#define SDPCM_WINDOW_VALUE(p) (((uint8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff) ++#define SDPCM_VERSION_OFFSET 6 /* Version # */ ++#define SDPCM_VERSION_VALUE(p) (((uint8 *)p)[SDPCM_VERSION_OFFSET] & 0xff) ++#define SDPCM_UNUSED_OFFSET 7 /* Spare */ ++#define SDPCM_UNUSED_VALUE(p) (((uint8 *)p)[SDPCM_UNUSED_OFFSET] & 0xff) ++ ++#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */ ++ ++/* logical channel numbers */ ++#define SDPCM_CONTROL_CHANNEL 0 /* Control Request/Response Channel Id */ ++#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */ ++#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */ ++#define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets (superframes) */ ++#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */ ++#define SDPCM_MAX_CHANNEL 15 ++ ++#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for eight-bit frame seq number */ ++ ++#define SDPCM_FLAG_RESVD0 0x01 ++#define SDPCM_FLAG_RESVD1 0x02 ++#define SDPCM_FLAG_GSPI_TXENAB 0x04 ++#define SDPCM_FLAG_GLOMDESC 0x08 /* Superframe descriptor mask */ ++ ++/* For GLOM_CHANNEL frames, use a flag to indicate descriptor frame */ ++#define SDPCM_GLOMDESC_FLAG (SDPCM_FLAG_GLOMDESC << SDPCM_FLAGS_SHIFT) ++ ++#define SDPCM_GLOMDESC(p) (((uint8 *)p)[1] & 0x80) ++ ++/* For TEST_CHANNEL packets, define another 4-byte header */ ++#define SDPCM_TEST_HDRLEN 4 /* Generally: Cmd(1), Ext(1), Len(2); ++ * Semantics of Ext byte depend on command. ++ * Len is current or requested frame length, not ++ * including test header; sent little-endian. ++ */ ++#define SDPCM_TEST_PKT_CNT_FLD_LEN 4 /* Packet count filed legth */ ++#define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext is a pattern id. */ ++#define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext is a pattern id. */ ++#define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext is a pattern id. */ ++#define SDPCM_TEST_BURST 0x04 /* Receiver to send a burst. Ext is a frame count ++ * (Backward compatabilty) Set frame count in a ++ * 4 byte filed adjacent to the HDR ++ */ ++#define SDPCM_TEST_SEND 0x05 /* Receiver sets send mode. Ext is boolean on/off ++ * Set frame count in a 4 byte filed adjacent to ++ * the HDR ++ */ ++ ++/* Handy macro for filling in datagen packets with a pattern */ ++#define SDPCM_TEST_FILL(byteno, id) ((uint8)(id + byteno)) ++ ++/* ++ * Software counters (first part matches hardware counters) ++ */ ++ ++typedef volatile struct { ++ uint32 cmd52rd; /* Cmd52RdCount, SDIO: cmd52 reads */ ++ uint32 cmd52wr; /* Cmd52WrCount, SDIO: cmd52 writes */ ++ uint32 cmd53rd; /* Cmd53RdCount, SDIO: cmd53 reads */ ++ uint32 cmd53wr; /* Cmd53WrCount, SDIO: cmd53 writes */ ++ uint32 abort; /* AbortCount, SDIO: aborts */ ++ uint32 datacrcerror; /* DataCrcErrorCount, SDIO: frames w/CRC error */ ++ uint32 rdoutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Rd Frm out of sync */ ++ uint32 wroutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Wr Frm out of sync */ ++ uint32 writebusy; /* WriteBusyCount, SDIO: device asserted "busy" */ ++ uint32 readwait; /* ReadWaitCount, SDIO: no data ready for a read cmd */ ++ uint32 readterm; /* ReadTermCount, SDIO: read frame termination cmds */ ++ uint32 writeterm; /* WriteTermCount, SDIO: write frames termination cmds */ ++ uint32 rxdescuflo; /* receive descriptor underflows */ ++ uint32 rxfifooflo; /* receive fifo overflows */ ++ uint32 txfifouflo; /* transmit fifo underflows */ ++ uint32 runt; /* runt (too short) frames recv'd from bus */ ++ uint32 badlen; /* frame's rxh len does not match its hw tag len */ ++ uint32 badcksum; /* frame's hw tag chksum doesn't agree with len value */ ++ uint32 seqbreak; /* break in sequence # space from one rx frame to the next */ ++ uint32 rxfcrc; /* frame rx header indicates crc error */ ++ uint32 rxfwoos; /* frame rx header indicates write out of sync */ ++ uint32 rxfwft; /* frame rx header indicates write frame termination */ ++ uint32 rxfabort; /* frame rx header indicates frame aborted */ ++ uint32 woosint; /* write out of sync interrupt */ ++ uint32 roosint; /* read out of sync interrupt */ ++ uint32 rftermint; /* read frame terminate interrupt */ ++ uint32 wftermint; /* write frame terminate interrupt */ ++} sdpcmd_cnt_t; ++ ++/* ++ * Register Access Macros ++ */ ++ ++#define SDIODREV_IS(var, val) ((var) == (val)) ++#define SDIODREV_GE(var, val) ((var) >= (val)) ++#define SDIODREV_GT(var, val) ((var) > (val)) ++#define SDIODREV_LT(var, val) ((var) < (val)) ++#define SDIODREV_LE(var, val) ((var) <= (val)) ++ ++#define SDIODDMAREG32(h, dir, chnl) \ ++ ((dir) == DMA_TX ? \ ++ (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].xmt) : \ ++ (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].rcv)) ++ ++#define SDIODDMAREG64(h, dir, chnl) \ ++ ((dir) == DMA_TX ? \ ++ (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].xmt) : \ ++ (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].rcv)) ++ ++#define SDIODDMAREG(h, dir, chnl) \ ++ (SDIODREV_LT((h)->corerev, 1) ? \ ++ SDIODDMAREG32((h), (dir), (chnl)) : \ ++ SDIODDMAREG64((h), (dir), (chnl))) ++ ++#define PCMDDMAREG(h, dir, chnl) \ ++ ((dir) == DMA_TX ? \ ++ (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.xmt) : \ ++ (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.rcv)) ++ ++#define SDPCMDMAREG(h, dir, chnl, coreid) \ ++ ((coreid) == SDIOD_CORE_ID ? \ ++ SDIODDMAREG(h, dir, chnl) : \ ++ PCMDDMAREG(h, dir, chnl)) ++ ++#define SDIODFIFOREG(h, corerev) \ ++ (SDIODREV_LT((corerev), 1) ? \ ++ ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod32.dmafifo)) : \ ++ ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod64.dmafifo))) ++ ++#define PCMDFIFOREG(h) \ ++ ((dma32diag_t *)(uintptr)&((h)->regs->dma.pcm32.dmafifo)) ++ ++#define SDPCMFIFOREG(h, coreid, corerev) \ ++ ((coreid) == SDIOD_CORE_ID ? \ ++ SDIODFIFOREG(h, corerev) : \ ++ PCMDFIFOREG(h)) ++ ++/* ++ * Shared structure between dongle and the host. ++ * The structure contains pointers to trap or assert information. ++ */ ++#define SDPCM_SHARED_VERSION 0x0001 ++#define SDPCM_SHARED_VERSION_MASK 0x00FF ++#define SDPCM_SHARED_ASSERT_BUILT 0x0100 ++#define SDPCM_SHARED_ASSERT 0x0200 ++#define SDPCM_SHARED_TRAP 0x0400 ++#define SDPCM_SHARED_IN_BRPT 0x0800 ++#define SDPCM_SHARED_SET_BRPT 0x1000 ++#define SDPCM_SHARED_PENDING_BRPT 0x2000 ++ ++typedef struct { ++ uint32 flags; ++ uint32 trap_addr; ++ uint32 assert_exp_addr; ++ uint32 assert_file_addr; ++ uint32 assert_line; ++ uint32 console_addr; /* Address of hndrte_cons_t */ ++ uint32 msgtrace_addr; ++ uint32 brpt_addr; ++} sdpcm_shared_t; ++ ++extern sdpcm_shared_t sdpcm_shared; ++ ++/* Function can be used to notify host of FW halt */ ++extern void sdpcmd_fwhalt(void); ++ ++#endif /* _bcmsdpcm_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmsdspi.h b/drivers/net/wireless/ap6211/include/bcmsdspi.h +new file mode 100755 +index 0000000..9a7496b +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmsdspi.h +@@ -0,0 +1,119 @@ ++/* ++ * SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdspi.h 294363 2011-11-06 23:02:20Z $ ++ */ ++#ifndef _BCM_SD_SPI_H ++#define _BCM_SD_SPI_H ++ ++#define BLOCK_SIZE_4318 64 ++#define BLOCK_SIZE_4328 512 ++ ++/* internal return code */ ++#define SUCCESS 0 ++#undef ERROR ++#define ERROR 1 ++ ++/* private bus modes */ ++#define SDIOH_MODE_SPI 0 ++ ++#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ ++#define USE_MULTIBLOCK 0x4 ++ ++struct sdioh_info { ++ uint cfg_bar; /* pci cfg address for bar */ ++ uint32 caps; /* cached value of capabilities reg */ ++ uint bar0; /* BAR0 for PCI Device */ ++ osl_t *osh; /* osh handler */ ++ void *controller; /* Pointer to SPI Controller's private data struct */ ++ ++ uint lockcount; /* nest count of sdspi_lock() calls */ ++ bool client_intr_enabled; /* interrupt connnected flag */ ++ bool intr_handler_valid; /* client driver interrupt handler valid */ ++ sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ ++ void *intr_handler_arg; /* argument to call interrupt handler */ ++ bool initialized; /* card initialized */ ++ uint32 target_dev; /* Target device ID */ ++ uint32 intmask; /* Current active interrupts */ ++ void *sdos_info; /* Pointer to per-OS private data */ ++ ++ uint32 controller_type; /* Host controller type */ ++ uint8 version; /* Host Controller Spec Compliance Version */ ++ uint irq; /* Client irq */ ++ uint32 intrcount; /* Client interrupts */ ++ uint32 local_intrcount; /* Controller interrupts */ ++ bool host_init_done; /* Controller initted */ ++ bool card_init_done; /* Client SDIO interface initted */ ++ bool polled_mode; /* polling for command completion */ ++ ++ bool sd_use_dma; /* DMA on CMD53 */ ++ bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ ++ /* Must be on for sd_multiblock to be effective */ ++ bool use_client_ints; /* If this is false, make sure to restore */ ++ bool got_hcint; /* Host Controller interrupt. */ ++ /* polling hack in wl_linux.c:wl_timer() */ ++ int adapter_slot; /* Maybe dealing with multiple slots/controllers */ ++ int sd_mode; /* SD1/SD4/SPI */ ++ int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ ++ uint32 data_xfer_count; /* Current register transfer size */ ++ uint32 cmd53_wr_data; /* Used to pass CMD53 write data */ ++ uint32 card_response; /* Used to pass back response status byte */ ++ uint32 card_rsp_data; /* Used to pass back response data word */ ++ uint16 card_rca; /* Current Address */ ++ uint8 num_funcs; /* Supported funcs on client */ ++ uint32 com_cis_ptr; ++ uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; ++ void *dma_buf; ++ ulong dma_phys; ++ int r_cnt; /* rx count */ ++ int t_cnt; /* tx_count */ ++}; ++ ++/************************************************************ ++ * Internal interfaces: per-port references into bcmsdspi.c ++ */ ++ ++/* Global message bits */ ++extern uint sd_msglevel; ++ ++/************************************************************** ++ * Internal interfaces: bcmsdspi.c references to per-port code ++ */ ++ ++/* Register mapping routines */ ++extern uint32 *spi_reg_map(osl_t *osh, uintptr addr, int size); ++extern void spi_reg_unmap(osl_t *osh, uintptr addr, int size); ++ ++/* Interrupt (de)registration routines */ ++extern int spi_register_irq(sdioh_info_t *sd, uint irq); ++extern void spi_free_irq(uint irq, sdioh_info_t *sd); ++ ++/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ ++extern void spi_lock(sdioh_info_t *sd); ++extern void spi_unlock(sdioh_info_t *sd); ++ ++/* Allocate/init/free per-OS private data */ ++extern int spi_osinit(sdioh_info_t *sd); ++extern void spi_osfree(sdioh_info_t *sd); ++ ++#endif /* _BCM_SD_SPI_H */ +diff --git a/drivers/net/wireless/ap6211/include/bcmsdstd.h b/drivers/net/wireless/ap6211/include/bcmsdstd.h +new file mode 100755 +index 0000000..1c854b2 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmsdstd.h +@@ -0,0 +1,248 @@ ++0/* ++ * 'Standard' SDIO HOST CONTROLLER driver ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmsdstd.h 347614 2012-07-27 10:24:51Z $ ++ */ ++#ifndef _BCM_SD_STD_H ++#define _BCM_SD_STD_H ++ ++#define sd_sync_dma(sd, read, nbytes) ++#define sd_init_dma(sd) ++#define sd_ack_intr(sd) ++#define sd_wakeup(sd); ++/* Allocate/init/free per-OS private data */ ++extern int sdstd_osinit(sdioh_info_t *sd); ++extern void sdstd_osfree(sdioh_info_t *sd); ++ ++#define BLOCK_SIZE_4318 64 ++#define BLOCK_SIZE_4328 512 ++ ++/* internal return code */ ++#define SUCCESS 0 ++#define ERROR 1 ++ ++/* private bus modes */ ++#define SDIOH_MODE_SPI 0 ++#define SDIOH_MODE_SD1 1 ++#define SDIOH_MODE_SD4 2 ++ ++#define MAX_SLOTS 6 /* For PCI: Only 6 BAR entries => 6 slots */ ++#define SDIOH_REG_WINSZ 0x100 /* Number of registers in Standard Host Controller */ ++ ++#define SDIOH_TYPE_ARASAN_HDK 1 ++#define SDIOH_TYPE_BCM27XX 2 ++#define SDIOH_TYPE_TI_PCIXX21 4 /* TI PCIxx21 Standard Host Controller */ ++#define SDIOH_TYPE_RICOH_R5C822 5 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter */ ++#define SDIOH_TYPE_JMICRON 6 /* JMicron Standard SDIO Host Controller */ ++ ++/* For linux, allow yielding for dongle */ ++#define BCMSDYIELD ++ ++/* Expected card status value for CMD7 */ ++#define SDIOH_CMD7_EXP_STATUS 0x00001E00 ++ ++#define RETRIES_LARGE 100000 ++#define sdstd_os_yield(sd) do {} while (0) ++#define RETRIES_SMALL 100 ++ ++ ++#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ ++#define USE_MULTIBLOCK 0x4 ++ ++#define USE_FIFO 0x8 /* Fifo vs non-fifo */ ++ ++#define CLIENT_INTR 0x100 /* Get rid of this! */ ++ ++#define HC_INTR_RETUNING 0x1000 ++ ++ ++#ifdef BCMSDIOH_TXGLOM ++/* Setting the MAX limit to 10 */ ++#define SDIOH_MAXGLOM_SIZE 10 ++ ++typedef struct glom_buf { ++ uint32 count; /* Total number of pkts queued */ ++ void *dma_buf_arr[SDIOH_MAXGLOM_SIZE]; /* Frame address */ ++ ulong dma_phys_arr[SDIOH_MAXGLOM_SIZE]; /* DMA_MAPed address of frames */ ++ uint16 nbytes[SDIOH_MAXGLOM_SIZE]; /* Size of each frame */ ++} glom_buf_t; ++#endif ++ ++struct sdioh_info { ++ uint cfg_bar; /* pci cfg address for bar */ ++ uint32 caps; /* cached value of capabilities reg */ ++ uint32 curr_caps; /* max current capabilities reg */ ++ ++ osl_t *osh; /* osh handler */ ++ volatile char *mem_space; /* pci device memory va */ ++ uint lockcount; /* nest count of sdstd_lock() calls */ ++ bool client_intr_enabled; /* interrupt connnected flag */ ++ bool intr_handler_valid; /* client driver interrupt handler valid */ ++ sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ ++ void *intr_handler_arg; /* argument to call interrupt handler */ ++ bool initialized; /* card initialized */ ++ uint target_dev; /* Target device ID */ ++ uint16 intmask; /* Current active interrupts */ ++ void *sdos_info; /* Pointer to per-OS private data */ ++ ++ uint32 controller_type; /* Host controller type */ ++ uint8 version; /* Host Controller Spec Compliance Version */ ++ uint irq; /* Client irq */ ++ int intrcount; /* Client interrupts */ ++ int local_intrcount; /* Controller interrupts */ ++ bool host_init_done; /* Controller initted */ ++ bool card_init_done; /* Client SDIO interface initted */ ++ bool polled_mode; /* polling for command completion */ ++ ++ bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ ++ /* Must be on for sd_multiblock to be effective */ ++ bool use_client_ints; /* If this is false, make sure to restore */ ++ /* polling hack in wl_linux.c:wl_timer() */ ++ int adapter_slot; /* Maybe dealing with multiple slots/controllers */ ++ int sd_mode; /* SD1/SD4/SPI */ ++ int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ ++ uint32 data_xfer_count; /* Current transfer */ ++ uint16 card_rca; /* Current Address */ ++ int8 sd_dma_mode; /* DMA Mode (PIO, SDMA, ... ADMA2) on CMD53 */ ++ uint8 num_funcs; /* Supported funcs on client */ ++ uint32 com_cis_ptr; ++ uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; ++ void *dma_buf; /* DMA Buffer virtual address */ ++ ulong dma_phys; /* DMA Buffer physical address */ ++ void *adma2_dscr_buf; /* ADMA2 Descriptor Buffer virtual address */ ++ ulong adma2_dscr_phys; /* ADMA2 Descriptor Buffer physical address */ ++ ++ /* adjustments needed to make the dma align properly */ ++ void *dma_start_buf; ++ ulong dma_start_phys; ++ uint alloced_dma_size; ++ void *adma2_dscr_start_buf; ++ ulong adma2_dscr_start_phys; ++ uint alloced_adma2_dscr_size; ++ ++ int r_cnt; /* rx count */ ++ int t_cnt; /* tx_count */ ++ bool got_hcint; /* local interrupt flag */ ++ uint16 last_intrstatus; /* to cache intrstatus */ ++ int host_UHSISupported; /* whether UHSI is supported for HC. */ ++ int card_UHSI_voltage_Supported; /* whether UHSI is supported for ++ * Card in terms of Voltage [1.8 or 3.3]. ++ */ ++ int global_UHSI_Supp; /* type of UHSI support in both host and card. ++ * HOST_SDR_UNSUPP: capabilities not supported/matched ++ * HOST_SDR_12_25: SDR12 and SDR25 supported ++ * HOST_SDR_50_104_DDR: one of SDR50/SDR104 or DDR50 supptd ++ */ ++ volatile int sd3_dat_state; /* data transfer state used for retuning check */ ++ volatile int sd3_tun_state; /* tuning state used for retuning check */ ++ bool sd3_tuning_reqd; /* tuning requirement parameter */ ++ uint32 caps3; /* cached value of 32 MSbits capabilities reg (SDIO 3.0) */ ++#ifdef BCMSDIOH_TXGLOM ++ glom_buf_t glom_info; /* pkt information used for glomming */ ++ uint txglom_mode; /* Txglom mode: 0 - copy, 1 - multi-descriptor */ ++#endif ++}; ++ ++#define DMA_MODE_NONE 0 ++#define DMA_MODE_SDMA 1 ++#define DMA_MODE_ADMA1 2 ++#define DMA_MODE_ADMA2 3 ++#define DMA_MODE_ADMA2_64 4 ++#define DMA_MODE_AUTO -1 ++ ++#define USE_DMA(sd) ((bool)((sd->sd_dma_mode > 0) ? TRUE : FALSE)) ++ ++/* States for Tuning and corr data */ ++#define TUNING_IDLE 0 ++#define TUNING_START 1 ++#define TUNING_START_AFTER_DAT 2 ++#define TUNING_ONGOING 3 ++ ++#define DATA_TRANSFER_IDLE 0 ++#define DATA_TRANSFER_ONGOING 1 ++ ++#define CHECK_TUNING_PRE_DATA 1 ++#define CHECK_TUNING_POST_DATA 2 ++ ++/************************************************************ ++ * Internal interfaces: per-port references into bcmsdstd.c ++ */ ++ ++/* Global message bits */ ++extern uint sd_msglevel; ++ ++/* OS-independent interrupt handler */ ++extern bool check_client_intr(sdioh_info_t *sd); ++ ++/* Core interrupt enable/disable of device interrupts */ ++extern void sdstd_devintr_on(sdioh_info_t *sd); ++extern void sdstd_devintr_off(sdioh_info_t *sd); ++ ++/* Enable/disable interrupts for local controller events */ ++extern void sdstd_intrs_on(sdioh_info_t *sd, uint16 norm, uint16 err); ++extern void sdstd_intrs_off(sdioh_info_t *sd, uint16 norm, uint16 err); ++ ++/* Wait for specified interrupt and error bits to be set */ ++extern void sdstd_spinbits(sdioh_info_t *sd, uint16 norm, uint16 err); ++ ++ ++/************************************************************** ++ * Internal interfaces: bcmsdstd.c references to per-port code ++ */ ++ ++/* Register mapping routines */ ++extern uint32 *sdstd_reg_map(osl_t *osh, int32 addr, int size); ++extern void sdstd_reg_unmap(osl_t *osh, int32 addr, int size); ++ ++/* Interrupt (de)registration routines */ ++extern int sdstd_register_irq(sdioh_info_t *sd, uint irq); ++extern void sdstd_free_irq(uint irq, sdioh_info_t *sd); ++ ++/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ ++extern void sdstd_lock(sdioh_info_t *sd); ++extern void sdstd_unlock(sdioh_info_t *sd); ++extern void sdstd_waitlockfree(sdioh_info_t *sd); ++ ++/* OS-specific wait-for-interrupt-or-status */ ++extern int sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield, uint16 *bits); ++ ++/* used by bcmsdstd_linux [implemented in sdstd] */ ++extern void sdstd_3_enable_retuning_int(sdioh_info_t *sd); ++extern void sdstd_3_disable_retuning_int(sdioh_info_t *sd); ++extern bool sdstd_3_is_retuning_int_set(sdioh_info_t *sd); ++extern void sdstd_3_check_and_do_tuning(sdioh_info_t *sd, int tuning_param); ++extern bool sdstd_3_check_and_set_retuning(sdioh_info_t *sd); ++extern int sdstd_3_get_tune_state(sdioh_info_t *sd); ++extern int sdstd_3_get_data_state(sdioh_info_t *sd); ++extern void sdstd_3_set_tune_state(sdioh_info_t *sd, int state); ++extern void sdstd_3_set_data_state(sdioh_info_t *sd, int state); ++extern uint8 sdstd_3_get_tuning_exp(sdioh_info_t *sd); ++extern uint32 sdstd_3_get_uhsi_clkmode(sdioh_info_t *sd); ++extern int sdstd_3_clk_tuning(sdioh_info_t *sd, uint32 sd3ClkMode); ++ ++/* used by sdstd [implemented in bcmsdstd_linux/ndis] */ ++extern void sdstd_3_start_tuning(sdioh_info_t *sd); ++extern void sdstd_3_osinit_tuning(sdioh_info_t *sd); ++extern void sdstd_3_osclean_tuning(sdioh_info_t *sd); ++ ++#endif /* _BCM_SD_STD_H */ +diff --git a/drivers/net/wireless/ap6211/include/bcmspi.h b/drivers/net/wireless/ap6211/include/bcmspi.h +new file mode 100755 +index 0000000..e226cb1 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmspi.h +@@ -0,0 +1,40 @@ ++/* ++ * Broadcom SPI Low-Level Hardware Driver API ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmspi.h 241182 2011-02-17 21:50:03Z $ ++ */ ++#ifndef _BCM_SPI_H ++#define _BCM_SPI_H ++ ++extern void spi_devintr_off(sdioh_info_t *sd); ++extern void spi_devintr_on(sdioh_info_t *sd); ++extern bool spi_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor); ++extern bool spi_controller_highspeed_mode(sdioh_info_t *sd, bool hsmode); ++extern bool spi_check_client_intr(sdioh_info_t *sd, int *is_dev_intr); ++extern bool spi_hw_attach(sdioh_info_t *sd); ++extern bool spi_hw_detach(sdioh_info_t *sd); ++extern void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen); ++extern void spi_spinbits(sdioh_info_t *sd); ++extern void spi_waitbits(sdioh_info_t *sd, bool yield); ++ ++#endif /* _BCM_SPI_H */ +diff --git a/drivers/net/wireless/ap6211/include/bcmutils.h b/drivers/net/wireless/ap6211/include/bcmutils.h +new file mode 100755 +index 0000000..71af3dc +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmutils.h +@@ -0,0 +1,808 @@ ++/* ++ * Misc useful os-independent macros and functions. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmutils.h 354837 2012-09-04 06:58:44Z $ ++ */ ++ ++#ifndef _bcmutils_h_ ++#define _bcmutils_h_ ++ ++#define bcm_strcpy_s(dst, noOfElements, src) strcpy((dst), (src)) ++#define bcm_strncpy_s(dst, noOfElements, src, count) strncpy((dst), (src), (count)) ++#define bcm_strcat_s(dst, noOfElements, src) strcat((dst), (src)) ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#ifdef PKTQ_LOG ++#include ++#endif ++ ++/* ctype replacement */ ++#define _BCM_U 0x01 /* upper */ ++#define _BCM_L 0x02 /* lower */ ++#define _BCM_D 0x04 /* digit */ ++#define _BCM_C 0x08 /* cntrl */ ++#define _BCM_P 0x10 /* punct */ ++#define _BCM_S 0x20 /* white space (space/lf/tab) */ ++#define _BCM_X 0x40 /* hex digit */ ++#define _BCM_SP 0x80 /* hard space (0x20) */ ++ ++extern const unsigned char bcm_ctype[]; ++#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)]) ++ ++#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0) ++#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0) ++#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0) ++#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0) ++#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0) ++#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0) ++#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0) ++#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0) ++#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0) ++#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0) ++#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0) ++#define bcm_tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) ++#define bcm_toupper(c) (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c)) ++ ++/* Buffer structure for collecting string-formatted data ++* using bcm_bprintf() API. ++* Use bcm_binit() to initialize before use ++*/ ++ ++struct bcmstrbuf { ++ char *buf; /* pointer to current position in origbuf */ ++ unsigned int size; /* current (residual) size in bytes */ ++ char *origbuf; /* unmodified pointer to orignal buffer */ ++ unsigned int origsize; /* unmodified orignal buffer size in bytes */ ++}; ++ ++/* ** driver-only section ** */ ++#ifdef BCMDRIVER ++#include ++ ++#define GPIO_PIN_NOTDEFINED 0x20 /* Pin not defined */ ++ ++/* ++ * Spin at most 'us' microseconds while 'exp' is true. ++ * Caller should explicitly test 'exp' when this completes ++ * and take appropriate error action if 'exp' is still true. ++ */ ++#define SPINWAIT(exp, us) { \ ++ uint countdown = (us) + 9; \ ++ while ((exp) && (countdown >= 10)) {\ ++ OSL_DELAY(10); \ ++ countdown -= 10; \ ++ } \ ++} ++ ++/* osl multi-precedence packet queue */ ++#ifndef PKTQ_LEN_DEFAULT ++#define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */ ++#endif ++#ifndef PKTQ_MAX_PREC ++#define PKTQ_MAX_PREC 16 /* Maximum precedence levels */ ++#endif ++ ++typedef struct pktq_prec { ++ void *head; /* first packet to dequeue */ ++ void *tail; /* last packet to dequeue */ ++ uint16 len; /* number of queued packets */ ++ uint16 max; /* maximum number of queued packets */ ++} pktq_prec_t; ++ ++#ifdef PKTQ_LOG ++typedef struct { ++ uint32 requested; /* packets requested to be stored */ ++ uint32 stored; /* packets stored */ ++ uint32 saved; /* packets saved, ++ because a lowest priority queue has given away one packet ++ */ ++ uint32 selfsaved; /* packets saved, ++ because an older packet from the same queue has been dropped ++ */ ++ uint32 full_dropped; /* packets dropped, ++ because pktq is full with higher precedence packets ++ */ ++ uint32 dropped; /* packets dropped because pktq per that precedence is full */ ++ uint32 sacrificed; /* packets dropped, ++ in order to save one from a queue of a highest priority ++ */ ++ uint32 busy; /* packets droped because of hardware/transmission error */ ++ uint32 retry; /* packets re-sent because they were not received */ ++ uint32 ps_retry; /* packets retried again prior to moving power save mode */ ++ uint32 retry_drop; /* packets finally dropped after retry limit */ ++ uint32 max_avail; /* the high-water mark of the queue capacity for packets - ++ goes to zero as queue fills ++ */ ++ uint32 max_used; /* the high-water mark of the queue utilisation for packets - ++ increases with use ('inverse' of max_avail) ++ */ ++ uint32 queue_capacity; /* the maximum capacity of the queue */ ++} pktq_counters_t; ++#endif /* PKTQ_LOG */ ++ ++ ++#define PKTQ_COMMON \ ++ uint16 num_prec; /* number of precedences in use */ \ ++ uint16 hi_prec; /* rapid dequeue hint (>= highest non-empty prec) */ \ ++ uint16 max; /* total max packets */ \ ++ uint16 len; /* total number of packets */ ++ ++/* multi-priority pkt queue */ ++struct pktq { ++ PKTQ_COMMON ++ /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ ++ struct pktq_prec q[PKTQ_MAX_PREC]; ++#ifdef PKTQ_LOG ++ pktq_counters_t _prec_cnt[PKTQ_MAX_PREC]; /* Counters per queue */ ++#endif ++}; ++ ++/* simple, non-priority pkt queue */ ++struct spktq { ++ PKTQ_COMMON ++ /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ ++ struct pktq_prec q[1]; ++}; ++ ++#define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--) ++ ++/* fn(pkt, arg). return true if pkt belongs to if */ ++typedef bool (*ifpkt_cb_t)(void*, int); ++ ++#ifdef BCMPKTPOOL ++#define POOL_ENAB(pool) ((pool) && (pool)->inited) ++#define SHARED_POOL (pktpool_shared) ++#else /* BCMPKTPOOL */ ++#define POOL_ENAB(bus) 0 ++#define SHARED_POOL ((struct pktpool *)NULL) ++#endif /* BCMPKTPOOL */ ++ ++#ifndef PKTPOOL_LEN_MAX ++#define PKTPOOL_LEN_MAX 40 ++#endif /* PKTPOOL_LEN_MAX */ ++#define PKTPOOL_CB_MAX 3 ++ ++struct pktpool; ++typedef void (*pktpool_cb_t)(struct pktpool *pool, void *arg); ++typedef struct { ++ pktpool_cb_t cb; ++ void *arg; ++} pktpool_cbinfo_t; ++ ++#ifdef BCMDBG_POOL ++/* pkt pool debug states */ ++#define POOL_IDLE 0 ++#define POOL_RXFILL 1 ++#define POOL_RXDH 2 ++#define POOL_RXD11 3 ++#define POOL_TXDH 4 ++#define POOL_TXD11 5 ++#define POOL_AMPDU 6 ++#define POOL_TXENQ 7 ++ ++typedef struct { ++ void *p; ++ uint32 cycles; ++ uint32 dur; ++} pktpool_dbg_t; ++ ++typedef struct { ++ uint8 txdh; /* tx to host */ ++ uint8 txd11; /* tx to d11 */ ++ uint8 enq; /* waiting in q */ ++ uint8 rxdh; /* rx from host */ ++ uint8 rxd11; /* rx from d11 */ ++ uint8 rxfill; /* dma_rxfill */ ++ uint8 idle; /* avail in pool */ ++} pktpool_stats_t; ++#endif /* BCMDBG_POOL */ ++ ++typedef struct pktpool { ++ bool inited; ++ uint16 r; ++ uint16 w; ++ uint16 len; ++ uint16 maxlen; ++ uint16 plen; ++ bool istx; ++ bool empty; ++ uint8 cbtoggle; ++ uint8 cbcnt; ++ uint8 ecbcnt; ++ bool emptycb_disable; ++ pktpool_cbinfo_t *availcb_excl; ++ pktpool_cbinfo_t cbs[PKTPOOL_CB_MAX]; ++ pktpool_cbinfo_t ecbs[PKTPOOL_CB_MAX]; ++ void *q[PKTPOOL_LEN_MAX + 1]; ++ ++#ifdef BCMDBG_POOL ++ uint8 dbg_cbcnt; ++ pktpool_cbinfo_t dbg_cbs[PKTPOOL_CB_MAX]; ++ uint16 dbg_qlen; ++ pktpool_dbg_t dbg_q[PKTPOOL_LEN_MAX + 1]; ++#endif ++} pktpool_t; ++ ++extern pktpool_t *pktpool_shared; ++ ++extern int pktpool_init(osl_t *osh, pktpool_t *pktp, int *pktplen, int plen, bool istx); ++extern int pktpool_deinit(osl_t *osh, pktpool_t *pktp); ++extern int pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal); ++extern void* pktpool_get(pktpool_t *pktp); ++extern void pktpool_free(pktpool_t *pktp, void *p); ++extern int pktpool_add(pktpool_t *pktp, void *p); ++extern uint16 pktpool_avail(pktpool_t *pktp); ++extern int pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp); ++extern int pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb); ++extern int pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); ++extern int pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); ++extern int pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen); ++extern int pktpool_setmaxlen_strict(osl_t *osh, pktpool_t *pktp, uint16 maxlen); ++extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable); ++extern bool pktpool_emptycb_disabled(pktpool_t *pktp); ++ ++#define POOLPTR(pp) ((pktpool_t *)(pp)) ++#define pktpool_len(pp) (POOLPTR(pp)->len - 1) ++#define pktpool_plen(pp) (POOLPTR(pp)->plen) ++#define pktpool_maxlen(pp) (POOLPTR(pp)->maxlen) ++ ++#ifdef BCMDBG_POOL ++extern int pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); ++extern int pktpool_start_trigger(pktpool_t *pktp, void *p); ++extern int pktpool_dbg_dump(pktpool_t *pktp); ++extern int pktpool_dbg_notify(pktpool_t *pktp); ++extern int pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats); ++#endif /* BCMDBG_POOL */ ++ ++/* forward definition of ether_addr structure used by some function prototypes */ ++ ++struct ether_addr; ++ ++extern int ether_isbcast(const void *ea); ++extern int ether_isnulladdr(const void *ea); ++ ++/* operations on a specific precedence in packet queue */ ++ ++#define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max)) ++#define pktq_pmax(pq, prec) ((pq)->q[prec].max) ++#define pktq_plen(pq, prec) ((pq)->q[prec].len) ++#define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len) ++#define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max) ++#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0) ++ ++#define pktq_ppeek(pq, prec) ((pq)->q[prec].head) ++#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail) ++ ++extern void *pktq_penq(struct pktq *pq, int prec, void *p); ++extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); ++extern void *pktq_pdeq(struct pktq *pq, int prec); ++extern void *pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p); ++extern void *pktq_pdeq_tail(struct pktq *pq, int prec); ++/* Empty the queue at particular precedence level */ ++extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ++ ifpkt_cb_t fn, int arg); ++/* Remove a specified packet from its queue */ ++extern bool pktq_pdel(struct pktq *pq, void *p, int prec); ++ ++/* operations on a set of precedences in packet queue */ ++ ++extern int pktq_mlen(struct pktq *pq, uint prec_bmp); ++extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); ++extern void *pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out); ++ ++/* operations on packet queue as a whole */ ++ ++#define pktq_len(pq) ((int)(pq)->len) ++#define pktq_max(pq) ((int)(pq)->max) ++#define pktq_avail(pq) ((int)((pq)->max - (pq)->len)) ++#define pktq_full(pq) ((pq)->len >= (pq)->max) ++#define pktq_empty(pq) ((pq)->len == 0) ++ ++/* operations for single precedence queues */ ++#define pktenq(pq, p) pktq_penq(((struct pktq *)(void *)pq), 0, (p)) ++#define pktenq_head(pq, p) pktq_penq_head(((struct pktq *)(void *)pq), 0, (p)) ++#define pktdeq(pq) pktq_pdeq(((struct pktq *)(void *)pq), 0) ++#define pktdeq_tail(pq) pktq_pdeq_tail(((struct pktq *)(void *)pq), 0) ++#define pktqinit(pq, len) pktq_init(((struct pktq *)(void *)pq), 1, len) ++ ++extern void pktq_init(struct pktq *pq, int num_prec, int max_len); ++extern void pktq_set_max_plen(struct pktq *pq, int prec, int max_len); ++ ++/* prec_out may be NULL if caller is not interested in return value */ ++extern void *pktq_deq(struct pktq *pq, int *prec_out); ++extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); ++extern void *pktq_peek(struct pktq *pq, int *prec_out); ++extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); ++extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg); ++ ++/* externs */ ++/* packet */ ++extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf); ++extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf); ++extern uint pkttotlen(osl_t *osh, void *p); ++extern void *pktlast(osl_t *osh, void *p); ++extern uint pktsegcnt(osl_t *osh, void *p); ++extern uint pktsegcnt_war(osl_t *osh, void *p); ++extern uint8 *pktoffset(osl_t *osh, void *p, uint offset); ++ ++/* Get priority from a packet and pass it back in scb (or equiv) */ ++#define PKTPRIO_VDSCP 0x100 /* DSCP prio found after VLAN tag */ ++#define PKTPRIO_VLAN 0x200 /* VLAN prio found */ ++#define PKTPRIO_UPD 0x400 /* DSCP used to update VLAN prio */ ++#define PKTPRIO_DSCP 0x800 /* DSCP prio found */ ++ ++extern uint pktsetprio(void *pkt, bool update_vtag); ++ ++/* string */ ++extern int bcm_atoi(const char *s); ++extern ulong bcm_strtoul(const char *cp, char **endp, uint base); ++extern char *bcmstrstr(const char *haystack, const char *needle); ++extern char *bcmstrcat(char *dest, const char *src); ++extern char *bcmstrncat(char *dest, const char *src, uint size); ++extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen); ++char* bcmstrtok(char **string, const char *delimiters, char *tokdelim); ++int bcmstricmp(const char *s1, const char *s2); ++int bcmstrnicmp(const char* s1, const char* s2, int cnt); ++ ++ ++/* ethernet address */ ++extern char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf); ++extern int bcm_ether_atoe(const char *p, struct ether_addr *ea); ++ ++/* ip address */ ++struct ipv4_addr; ++extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf); ++ ++/* delay */ ++extern void bcm_mdelay(uint ms); ++/* variable access */ ++#define NVRAM_RECLAIM_CHECK(name) ++ ++extern char *getvar(char *vars, const char *name); ++extern int getintvar(char *vars, const char *name); ++extern int getintvararray(char *vars, const char *name, int index); ++extern int getintvararraysize(char *vars, const char *name); ++extern uint getgpiopin(char *vars, char *pin_name, uint def_pin); ++#define bcm_perf_enable() ++#define bcmstats(fmt) ++#define bcmlog(fmt, a1, a2) ++#define bcmdumplog(buf, size) *buf = '\0' ++#define bcmdumplogent(buf, idx) -1 ++ ++#define bcmtslog(tstamp, fmt, a1, a2) ++#define bcmprinttslogs() ++#define bcmprinttstamp(us) ++#define bcmdumptslog(buf, size) ++ ++extern char *bcm_nvram_vars(uint *length); ++extern int bcm_nvram_cache(void *sih); ++ ++/* Support for sharing code across in-driver iovar implementations. ++ * The intent is that a driver use this structure to map iovar names ++ * to its (private) iovar identifiers, and the lookup function to ++ * find the entry. Macros are provided to map ids and get/set actions ++ * into a single number space for a switch statement. ++ */ ++ ++/* iovar structure */ ++typedef struct bcm_iovar { ++ const char *name; /* name for lookup and display */ ++ uint16 varid; /* id for switch */ ++ uint16 flags; /* driver-specific flag bits */ ++ uint16 type; /* base type of argument */ ++ uint16 minlen; /* min length for buffer vars */ ++} bcm_iovar_t; ++ ++/* varid definitions are per-driver, may use these get/set bits */ ++ ++/* IOVar action bits for id mapping */ ++#define IOV_GET 0 /* Get an iovar */ ++#define IOV_SET 1 /* Set an iovar */ ++ ++/* Varid to actionid mapping */ ++#define IOV_GVAL(id) ((id) * 2) ++#define IOV_SVAL(id) ((id) * 2 + IOV_SET) ++#define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET) ++#define IOV_ID(actionid) (actionid >> 1) ++ ++/* flags are per-driver based on driver attributes */ ++ ++extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name); ++extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set); ++#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ ++ defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) ++extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); ++#endif ++#endif /* BCMDRIVER */ ++ ++/* Base type definitions */ ++#define IOVT_VOID 0 /* no value (implictly set only) */ ++#define IOVT_BOOL 1 /* any value ok (zero/nonzero) */ ++#define IOVT_INT8 2 /* integer values are range-checked */ ++#define IOVT_UINT8 3 /* unsigned int 8 bits */ ++#define IOVT_INT16 4 /* int 16 bits */ ++#define IOVT_UINT16 5 /* unsigned int 16 bits */ ++#define IOVT_INT32 6 /* int 32 bits */ ++#define IOVT_UINT32 7 /* unsigned int 32 bits */ ++#define IOVT_BUFFER 8 /* buffer is size-checked as per minlen */ ++#define BCM_IOVT_VALID(type) (((unsigned int)(type)) <= IOVT_BUFFER) ++ ++/* Initializer for IOV type strings */ ++#define BCM_IOV_TYPE_INIT { \ ++ "void", \ ++ "bool", \ ++ "int8", \ ++ "uint8", \ ++ "int16", \ ++ "uint16", \ ++ "int32", \ ++ "uint32", \ ++ "buffer", \ ++ "" } ++ ++#define BCM_IOVT_IS_INT(type) (\ ++ (type == IOVT_BOOL) || \ ++ (type == IOVT_INT8) || \ ++ (type == IOVT_UINT8) || \ ++ (type == IOVT_INT16) || \ ++ (type == IOVT_UINT16) || \ ++ (type == IOVT_INT32) || \ ++ (type == IOVT_UINT32)) ++ ++/* ** driver/apps-shared section ** */ ++ ++#define BCME_STRLEN 64 /* Max string length for BCM errors */ ++#define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST)) ++ ++ ++/* ++ * error codes could be added but the defined ones shouldn't be changed/deleted ++ * these error codes are exposed to the user code ++ * when ever a new error code is added to this list ++ * please update errorstring table with the related error string and ++ * update osl files with os specific errorcode map ++*/ ++ ++#define BCME_OK 0 /* Success */ ++#define BCME_ERROR -1 /* Error generic */ ++#define BCME_BADARG -2 /* Bad Argument */ ++#define BCME_BADOPTION -3 /* Bad option */ ++#define BCME_NOTUP -4 /* Not up */ ++#define BCME_NOTDOWN -5 /* Not down */ ++#define BCME_NOTAP -6 /* Not AP */ ++#define BCME_NOTSTA -7 /* Not STA */ ++#define BCME_BADKEYIDX -8 /* BAD Key Index */ ++#define BCME_RADIOOFF -9 /* Radio Off */ ++#define BCME_NOTBANDLOCKED -10 /* Not band locked */ ++#define BCME_NOCLK -11 /* No Clock */ ++#define BCME_BADRATESET -12 /* BAD Rate valueset */ ++#define BCME_BADBAND -13 /* BAD Band */ ++#define BCME_BUFTOOSHORT -14 /* Buffer too short */ ++#define BCME_BUFTOOLONG -15 /* Buffer too long */ ++#define BCME_BUSY -16 /* Busy */ ++#define BCME_NOTASSOCIATED -17 /* Not Associated */ ++#define BCME_BADSSIDLEN -18 /* Bad SSID len */ ++#define BCME_OUTOFRANGECHAN -19 /* Out of Range Channel */ ++#define BCME_BADCHAN -20 /* Bad Channel */ ++#define BCME_BADADDR -21 /* Bad Address */ ++#define BCME_NORESOURCE -22 /* Not Enough Resources */ ++#define BCME_UNSUPPORTED -23 /* Unsupported */ ++#define BCME_BADLEN -24 /* Bad length */ ++#define BCME_NOTREADY -25 /* Not Ready */ ++#define BCME_EPERM -26 /* Not Permitted */ ++#define BCME_NOMEM -27 /* No Memory */ ++#define BCME_ASSOCIATED -28 /* Associated */ ++#define BCME_RANGE -29 /* Not In Range */ ++#define BCME_NOTFOUND -30 /* Not Found */ ++#define BCME_WME_NOT_ENABLED -31 /* WME Not Enabled */ ++#define BCME_TSPEC_NOTFOUND -32 /* TSPEC Not Found */ ++#define BCME_ACM_NOTSUPPORTED -33 /* ACM Not Supported */ ++#define BCME_NOT_WME_ASSOCIATION -34 /* Not WME Association */ ++#define BCME_SDIO_ERROR -35 /* SDIO Bus Error */ ++#define BCME_DONGLE_DOWN -36 /* Dongle Not Accessible */ ++#define BCME_VERSION -37 /* Incorrect version */ ++#define BCME_TXFAIL -38 /* TX failure */ ++#define BCME_RXFAIL -39 /* RX failure */ ++#define BCME_NODEVICE -40 /* Device not present */ ++#define BCME_NMODE_DISABLED -41 /* NMODE disabled */ ++#define BCME_NONRESIDENT -42 /* access to nonresident overlay */ ++#define BCME_LAST BCME_NONRESIDENT ++ ++/* These are collection of BCME Error strings */ ++#define BCMERRSTRINGTABLE { \ ++ "OK", \ ++ "Undefined error", \ ++ "Bad Argument", \ ++ "Bad Option", \ ++ "Not up", \ ++ "Not down", \ ++ "Not AP", \ ++ "Not STA", \ ++ "Bad Key Index", \ ++ "Radio Off", \ ++ "Not band locked", \ ++ "No clock", \ ++ "Bad Rate valueset", \ ++ "Bad Band", \ ++ "Buffer too short", \ ++ "Buffer too long", \ ++ "Busy", \ ++ "Not Associated", \ ++ "Bad SSID len", \ ++ "Out of Range Channel", \ ++ "Bad Channel", \ ++ "Bad Address", \ ++ "Not Enough Resources", \ ++ "Unsupported", \ ++ "Bad length", \ ++ "Not Ready", \ ++ "Not Permitted", \ ++ "No Memory", \ ++ "Associated", \ ++ "Not In Range", \ ++ "Not Found", \ ++ "WME Not Enabled", \ ++ "TSPEC Not Found", \ ++ "ACM Not Supported", \ ++ "Not WME Association", \ ++ "SDIO Bus Error", \ ++ "Dongle Not Accessible", \ ++ "Incorrect version", \ ++ "TX Failure", \ ++ "RX Failure", \ ++ "Device Not Present", \ ++ "NMODE Disabled", \ ++ "Nonresident overlay access", \ ++} ++ ++#ifndef ABS ++#define ABS(a) (((a) < 0) ? -(a) : (a)) ++#endif /* ABS */ ++ ++#ifndef MIN ++#define MIN(a, b) (((a) < (b)) ? (a) : (b)) ++#endif /* MIN */ ++ ++#ifndef MAX ++#define MAX(a, b) (((a) > (b)) ? (a) : (b)) ++#endif /* MAX */ ++ ++#define CEIL(x, y) (((x) + ((y) - 1)) / (y)) ++#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) ++#define ISALIGNED(a, x) (((uintptr)(a) & ((x) - 1)) == 0) ++#define ALIGN_ADDR(addr, boundary) (void *)(((uintptr)(addr) + (boundary) - 1) \ ++ & ~((boundary) - 1)) ++#define ALIGN_SIZE(size, boundary) (((size) + (boundary) - 1) \ ++ & ~((boundary) - 1)) ++#define ISPOWEROF2(x) ((((x) - 1) & (x)) == 0) ++#define VALID_MASK(mask) !((mask) & ((mask) + 1)) ++ ++#ifndef OFFSETOF ++#ifdef __ARMCC_VERSION ++/* ++ * The ARM RVCT compiler complains when using OFFSETOF where a constant ++ * expression is expected, such as an initializer for a static object. ++ * offsetof from the runtime library doesn't have that problem. ++ */ ++#include ++#define OFFSETOF(type, member) offsetof(type, member) ++#else ++#define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member) ++#endif /* __ARMCC_VERSION */ ++#endif /* OFFSETOF */ ++ ++#ifndef ARRAYSIZE ++#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) ++#endif ++ ++/* Reference a function; used to prevent a static function from being optimized out */ ++extern void *_bcmutils_dummy_fn; ++#define REFERENCE_FUNCTION(f) (_bcmutils_dummy_fn = (void *)(f)) ++ ++/* bit map related macros */ ++#ifndef setbit ++#ifndef NBBY /* the BSD family defines NBBY */ ++#define NBBY 8 /* 8 bits per byte */ ++#endif /* #ifndef NBBY */ ++#define setbit(a, i) (((uint8 *)a)[(i) / NBBY] |= 1 << ((i) % NBBY)) ++#define clrbit(a, i) (((uint8 *)a)[(i) / NBBY] &= ~(1 << ((i) % NBBY))) ++#define isset(a, i) (((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) ++#define isclr(a, i) ((((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) == 0) ++#endif /* setbit */ ++ ++#define NBITS(type) (sizeof(type) * 8) ++#define NBITVAL(nbits) (1 << (nbits)) ++#define MAXBITVAL(nbits) ((1 << (nbits)) - 1) ++#define NBITMASK(nbits) MAXBITVAL(nbits) ++#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8) ++ ++/* basic mux operation - can be optimized on several architectures */ ++#define MUX(pred, true, false) ((pred) ? (true) : (false)) ++ ++/* modulo inc/dec - assumes x E [0, bound - 1] */ ++#define MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 1) ++#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1) ++ ++/* modulo inc/dec, bound = 2^k */ ++#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1)) ++#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1)) ++ ++/* modulo add/sub - assumes x, y E [0, bound - 1] */ ++#define MODADD(x, y, bound) \ ++ MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y)) ++#define MODSUB(x, y, bound) \ ++ MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y)) ++ ++/* module add/sub, bound = 2^k */ ++#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1)) ++#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1)) ++ ++/* crc defines */ ++#define CRC8_INIT_VALUE 0xff /* Initial CRC8 checksum value */ ++#define CRC8_GOOD_VALUE 0x9f /* Good final CRC8 checksum value */ ++#define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */ ++#define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */ ++#define CRC32_INIT_VALUE 0xffffffff /* Initial CRC32 checksum value */ ++#define CRC32_GOOD_VALUE 0xdebb20e3 /* Good final CRC32 checksum value */ ++ ++/* use for direct output of MAC address in printf etc */ ++#define MACF "%02x:%02x:%02x:%02x:%02x:%02x" ++#define ETHERP_TO_MACF(ea) ((struct ether_addr *) (ea))->octet[0], \ ++ ((struct ether_addr *) (ea))->octet[1], \ ++ ((struct ether_addr *) (ea))->octet[2], \ ++ ((struct ether_addr *) (ea))->octet[3], \ ++ ((struct ether_addr *) (ea))->octet[4], \ ++ ((struct ether_addr *) (ea))->octet[5] ++ ++#define ETHER_TO_MACF(ea) (ea).octet[0], \ ++ (ea).octet[1], \ ++ (ea).octet[2], \ ++ (ea).octet[3], \ ++ (ea).octet[4], \ ++ (ea).octet[5] ++#if !defined(SIMPLE_MAC_PRINT) ++#define MACDBG "%02x:%02x:%02x:%02x:%02x:%02x" ++#define MAC2STRDBG(ea) (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] ++#else ++#define MACDBG "%02x:%02x:%02x" ++#define MAC2STRDBG(ea) (ea)[0], (ea)[4], (ea)[5] ++#endif /* SIMPLE_MAC_PRINT */ ++ ++/* bcm_format_flags() bit description structure */ ++typedef struct bcm_bit_desc { ++ uint32 bit; ++ const char* name; ++} bcm_bit_desc_t; ++ ++/* tag_ID/length/value_buffer tuple */ ++typedef struct bcm_tlv { ++ uint8 id; ++ uint8 len; ++ uint8 data[1]; ++} bcm_tlv_t; ++ ++/* Check that bcm_tlv_t fits into the given buflen */ ++#define bcm_valid_tlv(elt, buflen) ((buflen) >= 2 && (int)(buflen) >= (int)(2 + (elt)->len)) ++ ++/* buffer length for ethernet address from bcm_ether_ntoa() */ ++#define ETHER_ADDR_STR_LEN 18 /* 18-bytes of Ethernet address buffer length */ ++ ++/* crypto utility function */ ++/* 128-bit xor: *dst = *src1 xor *src2. dst1, src1 and src2 may have any alignment */ ++static INLINE void ++xor_128bit_block(const uint8 *src1, const uint8 *src2, uint8 *dst) ++{ ++ if ( ++#ifdef __i386__ ++ 1 || ++#endif ++ (((uintptr)src1 | (uintptr)src2 | (uintptr)dst) & 3) == 0) { ++ /* ARM CM3 rel time: 1229 (727 if alignment check could be omitted) */ ++ /* x86 supports unaligned. This version runs 6x-9x faster on x86. */ ++ ((uint32 *)dst)[0] = ((const uint32 *)src1)[0] ^ ((const uint32 *)src2)[0]; ++ ((uint32 *)dst)[1] = ((const uint32 *)src1)[1] ^ ((const uint32 *)src2)[1]; ++ ((uint32 *)dst)[2] = ((const uint32 *)src1)[2] ^ ((const uint32 *)src2)[2]; ++ ((uint32 *)dst)[3] = ((const uint32 *)src1)[3] ^ ((const uint32 *)src2)[3]; ++ } else { ++ /* ARM CM3 rel time: 4668 (4191 if alignment check could be omitted) */ ++ int k; ++ for (k = 0; k < 16; k++) ++ dst[k] = src1[k] ^ src2[k]; ++ } ++} ++ ++/* externs */ ++/* crc */ ++extern uint8 hndcrc8(uint8 *p, uint nbytes, uint8 crc); ++extern uint16 hndcrc16(uint8 *p, uint nbytes, uint16 crc); ++extern uint32 hndcrc32(uint8 *p, uint nbytes, uint32 crc); ++ ++/* format/print */ ++#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ ++ defined(WLMSG_ASSOC) ++extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len); ++#endif ++ ++#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ ++ defined(WLMSG_ASSOC) || defined(WLMEDIA_PEAKRATE) ++extern int bcm_format_hex(char *str, const void *bytes, int len); ++#endif ++ ++extern const char *bcm_crypto_algo_name(uint algo); ++extern char *bcm_chipname(uint chipid, char *buf, uint len); ++extern char *bcm_brev_str(uint32 brev, char *buf); ++extern void printbig(char *buf); ++extern void prhex(const char *msg, uchar *buf, uint len); ++ ++/* IE parsing */ ++extern bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen); ++extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key); ++extern bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key); ++ ++/* bcmerror */ ++extern const char *bcmerrorstr(int bcmerror); ++extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key); ++ ++/* multi-bool data type: set of bools, mbool is true if any is set */ ++typedef uint32 mbool; ++#define mboolset(mb, bit) ((mb) |= (bit)) /* set one bool */ ++#define mboolclr(mb, bit) ((mb) &= ~(bit)) /* clear one bool */ ++#define mboolisset(mb, bit) (((mb) & (bit)) != 0) /* TRUE if one bool is set */ ++#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val))) ++ ++/* generic datastruct to help dump routines */ ++struct fielddesc { ++ const char *nameandfmt; ++ uint32 offset; ++ uint32 len; ++}; ++ ++extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size); ++extern void bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len); ++ ++extern void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount); ++extern int bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes); ++extern void bcm_print_bytes(const char *name, const uchar *cdata, int len); ++ ++typedef uint32 (*bcmutl_rdreg_rtn)(void *arg0, uint arg1, uint32 offset); ++extern uint bcmdumpfields(bcmutl_rdreg_rtn func_ptr, void *arg0, uint arg1, struct fielddesc *str, ++ char *buf, uint32 bufsize); ++extern uint bcm_bitcount(uint8 *bitmap, uint bytelength); ++ ++extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...); ++ ++/* power conversion */ ++extern uint16 bcm_qdbm_to_mw(uint8 qdbm); ++extern uint8 bcm_mw_to_qdbm(uint16 mw); ++extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len); ++ ++unsigned int process_nvram_vars(char *varbuf, unsigned int len); ++ ++#ifdef __cplusplus ++ } ++#endif ++ ++#endif /* _bcmutils_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmwifi_channels.h b/drivers/net/wireless/ap6211/include/bcmwifi_channels.h +new file mode 100755 +index 0000000..bc57aca +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmwifi_channels.h +@@ -0,0 +1,490 @@ ++/* ++ * Misc utility routines for WL and Apps ++ * This header file housing the define and function prototype use by ++ * both the wl driver, tools & Apps. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmwifi_channels.h 309193 2012-01-19 00:03:57Z $ ++ */ ++ ++#ifndef _bcmwifi_channels_h_ ++#define _bcmwifi_channels_h_ ++ ++ ++/* A chanspec holds the channel number, band, bandwidth and control sideband */ ++typedef uint16 chanspec_t; ++ ++/* channel defines */ ++#define CH_UPPER_SB 0x01 ++#define CH_LOWER_SB 0x02 ++#define CH_EWA_VALID 0x04 ++#define CH_80MHZ_APART 16 ++#define CH_40MHZ_APART 8 ++#define CH_20MHZ_APART 4 ++#define CH_10MHZ_APART 2 ++#define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */ ++#define CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */ ++#define MAXCHANNEL 224 /* max # supported channels. The max channel no is 216, ++ * this is that + 1 rounded up to a multiple of NBBY (8). ++ * DO NOT MAKE it > 255: channels are uint8's all over ++ */ ++#define CHSPEC_CTLOVLP(sp1, sp2, sep) ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < (sep) ++ ++/* All builds use the new 11ac ratespec/chanspec */ ++#undef D11AC_IOTYPES ++#define D11AC_IOTYPES ++ ++#ifndef D11AC_IOTYPES ++ ++#define WL_CHANSPEC_CHAN_MASK 0x00ff ++#define WL_CHANSPEC_CHAN_SHIFT 0 ++ ++#define WL_CHANSPEC_CTL_SB_MASK 0x0300 ++#define WL_CHANSPEC_CTL_SB_SHIFT 8 ++#define WL_CHANSPEC_CTL_SB_LOWER 0x0100 ++#define WL_CHANSPEC_CTL_SB_UPPER 0x0200 ++#define WL_CHANSPEC_CTL_SB_NONE 0x0300 ++ ++#define WL_CHANSPEC_BW_MASK 0x0C00 ++#define WL_CHANSPEC_BW_SHIFT 10 ++#define WL_CHANSPEC_BW_10 0x0400 ++#define WL_CHANSPEC_BW_20 0x0800 ++#define WL_CHANSPEC_BW_40 0x0C00 ++ ++#define WL_CHANSPEC_BAND_MASK 0xf000 ++#define WL_CHANSPEC_BAND_SHIFT 12 ++#ifdef WL_CHANSPEC_BAND_5G ++#undef WL_CHANSPEC_BAND_5G ++#endif ++#ifdef WL_CHANSPEC_BAND_2G ++#undef WL_CHANSPEC_BAND_2G ++#endif ++#define WL_CHANSPEC_BAND_5G 0x1000 ++#define WL_CHANSPEC_BAND_2G 0x2000 ++#define INVCHANSPEC 255 ++ ++/* channel defines */ ++#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? ((channel) - CH_10MHZ_APART) : 0) ++#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ ++ ((channel) + CH_10MHZ_APART) : 0) ++#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) ++#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ ++ WL_CHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \ ++ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) ++#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ ++ ((channel) + CH_20MHZ_APART) : 0) ++#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ ++ ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ ++ ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ ++ WL_CHANSPEC_BAND_5G)) ++#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) ++#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) ++ ++/* chanspec stores radio channel & flags to indicate control channel location, i.e. upper/lower */ ++#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK) ++#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK) ++ ++#ifdef WL11N_20MHZONLY ++ ++#define CHSPEC_IS10(chspec) 0 ++#define CHSPEC_IS20(chspec) 1 ++#ifndef CHSPEC_IS40 ++#define CHSPEC_IS40(chspec) 0 ++#endif ++ ++#else /* !WL11N_20MHZONLY */ ++ ++#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) ++#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) ++#ifndef CHSPEC_IS40 ++#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) ++#endif ++ ++#endif /* !WL11N_20MHZONLY */ ++ ++#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) ++#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) ++#define CHSPEC_SB_NONE(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_NONE) ++#define CHSPEC_SB_UPPER(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) ++#define CHSPEC_SB_LOWER(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) ++#define CHSPEC_CTL_CHAN(chspec) ((CHSPEC_SB_LOWER(chspec)) ? \ ++ (LOWER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK))) : \ ++ (UPPER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK)))) ++#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) ++ ++#define CHANSPEC_STR_LEN 8 ++ ++#else /* D11AC_IOTYPES */ ++ ++#define WL_CHANSPEC_CHAN_MASK 0x00ff ++#define WL_CHANSPEC_CHAN_SHIFT 0 ++#define WL_CHANSPEC_CHAN1_MASK 0x000f ++#define WL_CHANSPEC_CHAN1_SHIFT 0 ++#define WL_CHANSPEC_CHAN2_MASK 0x00f0 ++#define WL_CHANSPEC_CHAN2_SHIFT 4 ++ ++#define WL_CHANSPEC_CTL_SB_MASK 0x0700 ++#define WL_CHANSPEC_CTL_SB_SHIFT 8 ++#define WL_CHANSPEC_CTL_SB_LLL 0x0000 ++#define WL_CHANSPEC_CTL_SB_LLU 0x0100 ++#define WL_CHANSPEC_CTL_SB_LUL 0x0200 ++#define WL_CHANSPEC_CTL_SB_LUU 0x0300 ++#define WL_CHANSPEC_CTL_SB_ULL 0x0400 ++#define WL_CHANSPEC_CTL_SB_ULU 0x0500 ++#define WL_CHANSPEC_CTL_SB_UUL 0x0600 ++#define WL_CHANSPEC_CTL_SB_UUU 0x0700 ++#define WL_CHANSPEC_CTL_SB_LL WL_CHANSPEC_CTL_SB_LLL ++#define WL_CHANSPEC_CTL_SB_LU WL_CHANSPEC_CTL_SB_LLU ++#define WL_CHANSPEC_CTL_SB_UL WL_CHANSPEC_CTL_SB_LUL ++#define WL_CHANSPEC_CTL_SB_UU WL_CHANSPEC_CTL_SB_LUU ++#define WL_CHANSPEC_CTL_SB_L WL_CHANSPEC_CTL_SB_LLL ++#define WL_CHANSPEC_CTL_SB_U WL_CHANSPEC_CTL_SB_LLU ++#define WL_CHANSPEC_CTL_SB_LOWER WL_CHANSPEC_CTL_SB_LLL ++#define WL_CHANSPEC_CTL_SB_UPPER WL_CHANSPEC_CTL_SB_LLU ++ ++#define WL_CHANSPEC_BW_MASK 0x3800 ++#define WL_CHANSPEC_BW_SHIFT 11 ++#define WL_CHANSPEC_BW_5 0x0000 ++#define WL_CHANSPEC_BW_10 0x0800 ++#define WL_CHANSPEC_BW_20 0x1000 ++#define WL_CHANSPEC_BW_40 0x1800 ++#define WL_CHANSPEC_BW_80 0x2000 ++#define WL_CHANSPEC_BW_160 0x2800 ++#define WL_CHANSPEC_BW_8080 0x3000 ++ ++#define WL_CHANSPEC_BAND_MASK 0xc000 ++#define WL_CHANSPEC_BAND_SHIFT 14 ++#define WL_CHANSPEC_BAND_2G 0x0000 ++#define WL_CHANSPEC_BAND_3G 0x4000 ++#define WL_CHANSPEC_BAND_4G 0x8000 ++#define WL_CHANSPEC_BAND_5G 0xc000 ++#define INVCHANSPEC 255 ++ ++/* channel defines */ ++#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \ ++ ((channel) - CH_10MHZ_APART) : 0) ++#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ ++ ((channel) + CH_10MHZ_APART) : 0) ++#define LOWER_40_SB(channel) ((channel) - CH_20MHZ_APART) ++#define UPPER_40_SB(channel) ((channel) + CH_20MHZ_APART) ++#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) ++#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ ++ (((channel) <= CH_MAX_2G_CHANNEL) ? \ ++ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) ++#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ ++ ((channel) + CH_20MHZ_APART) : 0) ++#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ ++ ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ ++ ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ ++ WL_CHANSPEC_BAND_5G)) ++#define CH80MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ ++ ((channel) | (ctlsb) | \ ++ WL_CHANSPEC_BW_80 | WL_CHANSPEC_BAND_5G) ++#define CH160MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ ++ ((channel) | (ctlsb) | \ ++ WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G) ++ ++/* simple MACROs to get different fields of chanspec */ ++#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) ++#define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK) ++#define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK) ++#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) ++#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK) ++#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK) ++ ++#ifdef WL11N_20MHZONLY ++ ++#define CHSPEC_IS10(chspec) 0 ++#define CHSPEC_IS20(chspec) 1 ++#ifndef CHSPEC_IS40 ++#define CHSPEC_IS40(chspec) 0 ++#endif ++#ifndef CHSPEC_IS80 ++#define CHSPEC_IS80(chspec) 0 ++#endif ++#ifndef CHSPEC_IS160 ++#define CHSPEC_IS160(chspec) 0 ++#endif ++#ifndef CHSPEC_IS8080 ++#define CHSPEC_IS8080(chspec) 0 ++#endif ++ ++#else /* !WL11N_20MHZONLY */ ++ ++#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) ++#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) ++#ifndef CHSPEC_IS40 ++#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) ++#endif ++#ifndef CHSPEC_IS80 ++#define CHSPEC_IS80(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80) ++#endif ++#ifndef CHSPEC_IS160 ++#define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160) ++#endif ++#ifndef CHSPEC_IS8080 ++#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080) ++#endif ++ ++#endif /* !WL11N_20MHZONLY */ ++ ++#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) ++#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) ++#define CHSPEC_SB_UPPER(chspec) \ ++ ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) && \ ++ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) ++#define CHSPEC_SB_LOWER(chspec) \ ++ ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \ ++ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) ++#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) ++ ++/** ++ * Number of chars needed for wf_chspec_ntoa() destination character buffer. ++ */ ++#define CHANSPEC_STR_LEN 20 ++ ++ ++/* Legacy Chanspec defines ++ * These are the defines for the previous format of the chanspec_t ++ */ ++#define WL_LCHANSPEC_CHAN_MASK 0x00ff ++#define WL_LCHANSPEC_CHAN_SHIFT 0 ++ ++#define WL_LCHANSPEC_CTL_SB_MASK 0x0300 ++#define WL_LCHANSPEC_CTL_SB_SHIFT 8 ++#define WL_LCHANSPEC_CTL_SB_LOWER 0x0100 ++#define WL_LCHANSPEC_CTL_SB_UPPER 0x0200 ++#define WL_LCHANSPEC_CTL_SB_NONE 0x0300 ++ ++#define WL_LCHANSPEC_BW_MASK 0x0C00 ++#define WL_LCHANSPEC_BW_SHIFT 10 ++#define WL_LCHANSPEC_BW_10 0x0400 ++#define WL_LCHANSPEC_BW_20 0x0800 ++#define WL_LCHANSPEC_BW_40 0x0C00 ++ ++#define WL_LCHANSPEC_BAND_MASK 0xf000 ++#define WL_LCHANSPEC_BAND_SHIFT 12 ++#define WL_LCHANSPEC_BAND_5G 0x1000 ++#define WL_LCHANSPEC_BAND_2G 0x2000 ++ ++#define LCHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_LCHANSPEC_CHAN_MASK)) ++#define LCHSPEC_BAND(chspec) ((chspec) & WL_LCHANSPEC_BAND_MASK) ++#define LCHSPEC_CTL_SB(chspec) ((chspec) & WL_LCHANSPEC_CTL_SB_MASK) ++#define LCHSPEC_BW(chspec) ((chspec) & WL_LCHANSPEC_BW_MASK) ++#define LCHSPEC_IS10(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_10) ++#define LCHSPEC_IS20(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_20) ++#define LCHSPEC_IS40(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40) ++#define LCHSPEC_IS5G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_5G) ++#define LCHSPEC_IS2G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_2G) ++ ++#define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band))) ++ ++#endif /* D11AC_IOTYPES */ ++ ++/* ++ * WF_CHAN_FACTOR_* constants are used to calculate channel frequency ++ * given a channel number. ++ * chan_freq = chan_factor * 500Mhz + chan_number * 5 ++ */ ++ ++/** ++ * Channel Factor for the starting frequence of 2.4 GHz channels. ++ * The value corresponds to 2407 MHz. ++ */ ++#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */ ++ ++/** ++ * Channel Factor for the starting frequence of 5 GHz channels. ++ * The value corresponds to 5000 MHz. ++ */ ++#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */ ++ ++/** ++ * Channel Factor for the starting frequence of 4.9 GHz channels. ++ * The value corresponds to 4000 MHz. ++ */ ++#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */ ++ ++/* defined rate in 500kbps */ ++#define WLC_MAXRATE 108 /* in 500kbps units */ ++#define WLC_RATE_1M 2 /* in 500kbps units */ ++#define WLC_RATE_2M 4 /* in 500kbps units */ ++#define WLC_RATE_5M5 11 /* in 500kbps units */ ++#define WLC_RATE_11M 22 /* in 500kbps units */ ++#define WLC_RATE_6M 12 /* in 500kbps units */ ++#define WLC_RATE_9M 18 /* in 500kbps units */ ++#define WLC_RATE_12M 24 /* in 500kbps units */ ++#define WLC_RATE_18M 36 /* in 500kbps units */ ++#define WLC_RATE_24M 48 /* in 500kbps units */ ++#define WLC_RATE_36M 72 /* in 500kbps units */ ++#define WLC_RATE_48M 96 /* in 500kbps units */ ++#define WLC_RATE_54M 108 /* in 500kbps units */ ++ ++#define WLC_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */ ++ ++/** ++ * Convert chanspec to ascii string ++ * ++ * @param chspec chanspec format ++ * @param buf ascii string of chanspec ++ * ++ * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes ++ * ++ * @see CHANSPEC_STR_LEN ++ */ ++extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf); ++ ++/** ++ * Convert ascii string to chanspec ++ * ++ * @param a pointer to input string ++ * ++ * @return >= 0 if successful or 0 otherwise ++ */ ++extern chanspec_t wf_chspec_aton(const char *a); ++ ++/** ++ * Verify the chanspec fields are valid. ++ * ++ * Verify the chanspec is using a legal set field values, i.e. that the chanspec ++ * specified a band, bw, ctl_sb and channel and that the combination could be ++ * legal given some set of circumstances. ++ * ++ * @param chanspec input chanspec to verify ++ * ++ * @return TRUE if the chanspec is malformed, FALSE if it looks good. ++ */ ++extern bool wf_chspec_malformed(chanspec_t chanspec); ++ ++/** ++ * Verify the chanspec specifies a valid channel according to 802.11. ++ * ++ * @param chanspec input chanspec to verify ++ * ++ * @return TRUE if the chanspec is a valid 802.11 channel ++ */ ++extern bool wf_chspec_valid(chanspec_t chanspec); ++ ++/** ++ * Return the primary (control) channel. ++ * ++ * This function returns the channel number of the primary 20MHz channel. For ++ * 20MHz channels this is just the channel number. For 40MHz or wider channels ++ * it is the primary 20MHz channel specified by the chanspec. ++ * ++ * @param chspec input chanspec ++ * ++ * @return Returns the channel number of the primary 20MHz channel ++ */ ++extern uint8 wf_chspec_ctlchan(chanspec_t chspec); ++ ++/** ++ * Return the primary (control) chanspec. ++ * ++ * This function returns the chanspec of the primary 20MHz channel. For 20MHz ++ * channels this is just the chanspec. For 40MHz or wider channels it is the ++ * chanspec of the primary 20MHZ channel specified by the chanspec. ++ * ++ * @param chspec input chanspec ++ * ++ * @return Returns the chanspec of the primary 20MHz channel ++ */ ++extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec); ++ ++/** ++ * Return a channel number corresponding to a frequency. ++ * ++ * This function returns the chanspec for the primary 40MHz of an 80MHz channel. ++ * The control sideband specifies the same 20MHz channel that the 80MHz channel is using ++ * as the primary 20MHz channel. ++ */ ++extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec); ++ ++/* ++ * Return the channel number for a given frequency and base frequency. ++ * The returned channel number is relative to the given base frequency. ++ * If the given base frequency is zero, a base frequency of 5 GHz is assumed for ++ * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. ++ * ++ * Frequency is specified in MHz. ++ * The base frequency is specified as (start_factor * 500 kHz). ++ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for ++ * 2.4 GHz and 5 GHz bands. ++ * ++ * The returned channel will be in the range [1, 14] in the 2.4 GHz band ++ * and [0, 200] otherwise. ++ * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the ++ * frequency is not a 2.4 GHz channel, or if the frequency is not and even ++ * multiple of 5 MHz from the base frequency to the base plus 1 GHz. ++ * ++ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 ++ * ++ * @param freq frequency in MHz ++ * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz ++ * ++ * @return Returns a channel number ++ * ++ * @see WF_CHAN_FACTOR_2_4_G ++ * @see WF_CHAN_FACTOR_5_G ++ */ ++extern int wf_mhz2channel(uint freq, uint start_factor); ++ ++/** ++ * Return the center frequency in MHz of the given channel and base frequency. ++ * ++ * Return the center frequency in MHz of the given channel and base frequency. ++ * The channel number is interpreted relative to the given base frequency. ++ * ++ * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. ++ * The base frequency is specified as (start_factor * 500 kHz). ++ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for ++ * 2.4 GHz and 5 GHz bands. ++ * The channel range of [1, 14] is only checked for a start_factor of ++ * WF_CHAN_FACTOR_2_4_G (4814). ++ * Odd start_factors produce channels on .5 MHz boundaries, in which case ++ * the answer is rounded down to an integral MHz. ++ * -1 is returned for an out of range channel. ++ * ++ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 ++ * ++ * @param channel input channel number ++ * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz ++ * ++ * @return Returns a frequency in MHz ++ * ++ * @see WF_CHAN_FACTOR_2_4_G ++ * @see WF_CHAN_FACTOR_5_G ++ */ ++extern int wf_channel2mhz(uint channel, uint start_factor); ++ ++/** ++ * Convert ctl chan and bw to chanspec ++ * ++ * @param ctl_ch channel ++ * @param bw bandwidth ++ * ++ * @return > 0 if successful or 0 otherwise ++ * ++ */ ++extern uint16 wf_channel2chspec(uint ctl_ch, uint bw); ++ ++#endif /* _bcmwifi_channels_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/bcmwifi_rates.h b/drivers/net/wireless/ap6211/include/bcmwifi_rates.h +new file mode 100755 +index 0000000..ddc6ab5 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/bcmwifi_rates.h +@@ -0,0 +1,318 @@ ++/* ++ * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmwifi_rates.h 252708 2011-04-12 06:45:56Z $ ++ */ ++ ++#ifndef _bcmwifi_rates_h_ ++#define _bcmwifi_rates_h_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++ ++ ++#define WL_RATESET_SZ_DSSS 4 ++#define WL_RATESET_SZ_OFDM 8 ++#define WL_RATESET_SZ_HT_MCS 8 ++#define WL_RATESET_SZ_VHT_MCS 10 ++ ++#define WL_TX_CHAINS_MAX 3 ++ ++#define WL_RATE_DISABLED (-128) /* Power value corresponding to unsupported rate */ ++ ++/* Transmit channel bandwidths */ ++typedef enum wl_tx_bw { ++ WL_TX_BW_20, ++ WL_TX_BW_40, ++ WL_TX_BW_80, ++ WL_TX_BW_20IN40, ++ WL_TX_BW_20IN80, ++ WL_TX_BW_40IN80, ++ WL_TX_BW_ALL ++} wl_tx_bw_t; ++ ++ ++/* ++ * Transmit modes. ++ * Not all modes are listed here, only those required for disambiguation. e.g. SPEXP is not listed ++ */ ++typedef enum wl_tx_mode { ++ WL_TX_MODE_NONE, ++ WL_TX_MODE_STBC, ++ WL_TX_MODE_CDD, ++ WL_TX_MODE_SDM ++} wl_tx_mode_t; ++ ++ ++/* Number of transmit chains */ ++typedef enum wl_tx_chains { ++ WL_TX_CHAINS_1 = 1, ++ WL_TX_CHAINS_2, ++ WL_TX_CHAINS_3 ++} wl_tx_chains_t; ++ ++ ++/* Number of transmit streams */ ++typedef enum wl_tx_nss { ++ WL_TX_NSS_1 = 1, ++ WL_TX_NSS_2, ++ WL_TX_NSS_3 ++} wl_tx_nss_t; ++ ++ ++typedef enum clm_rates { ++ /************ ++ * 1 chain * ++ ************ ++ */ ++ ++ /* 1 Stream */ ++ WL_RATE_1X1_DSSS_1 = 0, ++ WL_RATE_1X1_DSSS_2 = 1, ++ WL_RATE_1X1_DSSS_5_5 = 2, ++ WL_RATE_1X1_DSSS_11 = 3, ++ ++ WL_RATE_1X1_OFDM_6 = 4, ++ WL_RATE_1X1_OFDM_9 = 5, ++ WL_RATE_1X1_OFDM_12 = 6, ++ WL_RATE_1X1_OFDM_18 = 7, ++ WL_RATE_1X1_OFDM_24 = 8, ++ WL_RATE_1X1_OFDM_36 = 9, ++ WL_RATE_1X1_OFDM_48 = 10, ++ WL_RATE_1X1_OFDM_54 = 11, ++ ++ WL_RATE_1X1_MCS0 = 12, ++ WL_RATE_1X1_MCS1 = 13, ++ WL_RATE_1X1_MCS2 = 14, ++ WL_RATE_1X1_MCS3 = 15, ++ WL_RATE_1X1_MCS4 = 16, ++ WL_RATE_1X1_MCS5 = 17, ++ WL_RATE_1X1_MCS6 = 18, ++ WL_RATE_1X1_MCS7 = 19, ++ ++ WL_RATE_1X1_VHT0SS1 = 12, ++ WL_RATE_1X1_VHT1SS1 = 13, ++ WL_RATE_1X1_VHT2SS1 = 14, ++ WL_RATE_1X1_VHT3SS1 = 15, ++ WL_RATE_1X1_VHT4SS1 = 16, ++ WL_RATE_1X1_VHT5SS1 = 17, ++ WL_RATE_1X1_VHT6SS1 = 18, ++ WL_RATE_1X1_VHT7SS1 = 19, ++ WL_RATE_1X1_VHT8SS1 = 20, ++ WL_RATE_1X1_VHT9SS1 = 21, ++ ++ ++ /************ ++ * 2 chains * ++ ************ ++ */ ++ ++ /* 1 Stream expanded + 1 */ ++ WL_RATE_1X2_DSSS_1 = 22, ++ WL_RATE_1X2_DSSS_2 = 23, ++ WL_RATE_1X2_DSSS_5_5 = 24, ++ WL_RATE_1X2_DSSS_11 = 25, ++ ++ WL_RATE_1X2_CDD_OFDM_6 = 26, ++ WL_RATE_1X2_CDD_OFDM_9 = 27, ++ WL_RATE_1X2_CDD_OFDM_12 = 28, ++ WL_RATE_1X2_CDD_OFDM_18 = 29, ++ WL_RATE_1X2_CDD_OFDM_24 = 30, ++ WL_RATE_1X2_CDD_OFDM_36 = 31, ++ WL_RATE_1X2_CDD_OFDM_48 = 32, ++ WL_RATE_1X2_CDD_OFDM_54 = 33, ++ ++ WL_RATE_1X2_CDD_MCS0 = 34, ++ WL_RATE_1X2_CDD_MCS1 = 35, ++ WL_RATE_1X2_CDD_MCS2 = 36, ++ WL_RATE_1X2_CDD_MCS3 = 37, ++ WL_RATE_1X2_CDD_MCS4 = 38, ++ WL_RATE_1X2_CDD_MCS5 = 39, ++ WL_RATE_1X2_CDD_MCS6 = 40, ++ WL_RATE_1X2_CDD_MCS7 = 41, ++ ++ WL_RATE_1X2_VHT0SS1 = 34, ++ WL_RATE_1X2_VHT1SS1 = 35, ++ WL_RATE_1X2_VHT2SS1 = 36, ++ WL_RATE_1X2_VHT3SS1 = 37, ++ WL_RATE_1X2_VHT4SS1 = 38, ++ WL_RATE_1X2_VHT5SS1 = 39, ++ WL_RATE_1X2_VHT6SS1 = 40, ++ WL_RATE_1X2_VHT7SS1 = 41, ++ WL_RATE_1X2_VHT8SS1 = 42, ++ WL_RATE_1X2_VHT9SS1 = 43, ++ ++ /* 2 Streams */ ++ WL_RATE_2X2_STBC_MCS0 = 44, ++ WL_RATE_2X2_STBC_MCS1 = 45, ++ WL_RATE_2X2_STBC_MCS2 = 46, ++ WL_RATE_2X2_STBC_MCS3 = 47, ++ WL_RATE_2X2_STBC_MCS4 = 48, ++ WL_RATE_2X2_STBC_MCS5 = 49, ++ WL_RATE_2X2_STBC_MCS6 = 50, ++ WL_RATE_2X2_STBC_MCS7 = 51, ++ ++ WL_RATE_2X2_STBC_VHT0SS1 = 44, ++ WL_RATE_2X2_STBC_VHT1SS1 = 45, ++ WL_RATE_2X2_STBC_VHT2SS1 = 46, ++ WL_RATE_2X2_STBC_VHT3SS1 = 47, ++ WL_RATE_2X2_STBC_VHT4SS1 = 48, ++ WL_RATE_2X2_STBC_VHT5SS1 = 49, ++ WL_RATE_2X2_STBC_VHT6SS1 = 50, ++ WL_RATE_2X2_STBC_VHT7SS1 = 51, ++ WL_RATE_2X2_STBC_VHT8SS1 = 52, ++ WL_RATE_2X2_STBC_VHT9SS1 = 53, ++ ++ WL_RATE_2X2_SDM_MCS8 = 54, ++ WL_RATE_2X2_SDM_MCS9 = 55, ++ WL_RATE_2X2_SDM_MCS10 = 56, ++ WL_RATE_2X2_SDM_MCS11 = 57, ++ WL_RATE_2X2_SDM_MCS12 = 58, ++ WL_RATE_2X2_SDM_MCS13 = 59, ++ WL_RATE_2X2_SDM_MCS14 = 60, ++ WL_RATE_2X2_SDM_MCS15 = 61, ++ ++ WL_RATE_2X2_VHT0SS2 = 54, ++ WL_RATE_2X2_VHT1SS2 = 55, ++ WL_RATE_2X2_VHT2SS2 = 56, ++ WL_RATE_2X2_VHT3SS2 = 57, ++ WL_RATE_2X2_VHT4SS2 = 58, ++ WL_RATE_2X2_VHT5SS2 = 59, ++ WL_RATE_2X2_VHT6SS2 = 60, ++ WL_RATE_2X2_VHT7SS2 = 61, ++ WL_RATE_2X2_VHT8SS2 = 62, ++ WL_RATE_2X2_VHT9SS2 = 63, ++ ++ ++ /************ ++ * 3 chains * ++ ************ ++ */ ++ ++ /* 1 Stream expanded + 2 */ ++ WL_RATE_1X3_DSSS_1 = 64, ++ WL_RATE_1X3_DSSS_2 = 65, ++ WL_RATE_1X3_DSSS_5_5 = 66, ++ WL_RATE_1X3_DSSS_11 = 67, ++ ++ WL_RATE_1X3_CDD_OFDM_6 = 68, ++ WL_RATE_1X3_CDD_OFDM_9 = 69, ++ WL_RATE_1X3_CDD_OFDM_12 = 70, ++ WL_RATE_1X3_CDD_OFDM_18 = 71, ++ WL_RATE_1X3_CDD_OFDM_24 = 72, ++ WL_RATE_1X3_CDD_OFDM_36 = 73, ++ WL_RATE_1X3_CDD_OFDM_48 = 74, ++ WL_RATE_1X3_CDD_OFDM_54 = 75, ++ ++ WL_RATE_1X3_CDD_MCS0 = 76, ++ WL_RATE_1X3_CDD_MCS1 = 77, ++ WL_RATE_1X3_CDD_MCS2 = 78, ++ WL_RATE_1X3_CDD_MCS3 = 79, ++ WL_RATE_1X3_CDD_MCS4 = 80, ++ WL_RATE_1X3_CDD_MCS5 = 81, ++ WL_RATE_1X3_CDD_MCS6 = 82, ++ WL_RATE_1X3_CDD_MCS7 = 83, ++ ++ WL_RATE_1X3_VHT0SS1 = 76, ++ WL_RATE_1X3_VHT1SS1 = 77, ++ WL_RATE_1X3_VHT2SS1 = 78, ++ WL_RATE_1X3_VHT3SS1 = 79, ++ WL_RATE_1X3_VHT4SS1 = 80, ++ WL_RATE_1X3_VHT5SS1 = 81, ++ WL_RATE_1X3_VHT6SS1 = 82, ++ WL_RATE_1X3_VHT7SS1 = 83, ++ WL_RATE_1X3_VHT8SS1 = 84, ++ WL_RATE_1X3_VHT9SS1 = 85, ++ ++ /* 2 Streams expanded + 1 */ ++ WL_RATE_2X3_STBC_MCS0 = 86, ++ WL_RATE_2X3_STBC_MCS1 = 87, ++ WL_RATE_2X3_STBC_MCS2 = 88, ++ WL_RATE_2X3_STBC_MCS3 = 89, ++ WL_RATE_2X3_STBC_MCS4 = 90, ++ WL_RATE_2X3_STBC_MCS5 = 91, ++ WL_RATE_2X3_STBC_MCS6 = 92, ++ WL_RATE_2X3_STBC_MCS7 = 93, ++ ++ WL_RATE_2X3_STBC_VHT0SS1 = 86, ++ WL_RATE_2X3_STBC_VHT1SS1 = 87, ++ WL_RATE_2X3_STBC_VHT2SS1 = 88, ++ WL_RATE_2X3_STBC_VHT3SS1 = 89, ++ WL_RATE_2X3_STBC_VHT4SS1 = 90, ++ WL_RATE_2X3_STBC_VHT5SS1 = 91, ++ WL_RATE_2X3_STBC_VHT6SS1 = 92, ++ WL_RATE_2X3_STBC_VHT7SS1 = 93, ++ WL_RATE_2X3_STBC_VHT8SS1 = 94, ++ WL_RATE_2X3_STBC_VHT9SS1 = 95, ++ ++ WL_RATE_2X3_SDM_MCS8 = 96, ++ WL_RATE_2X3_SDM_MCS9 = 97, ++ WL_RATE_2X3_SDM_MCS10 = 98, ++ WL_RATE_2X3_SDM_MCS11 = 99, ++ WL_RATE_2X3_SDM_MCS12 = 100, ++ WL_RATE_2X3_SDM_MCS13 = 101, ++ WL_RATE_2X3_SDM_MCS14 = 102, ++ WL_RATE_2X3_SDM_MCS15 = 103, ++ ++ WL_RATE_2X3_VHT0SS2 = 96, ++ WL_RATE_2X3_VHT1SS2 = 97, ++ WL_RATE_2X3_VHT2SS2 = 98, ++ WL_RATE_2X3_VHT3SS2 = 99, ++ WL_RATE_2X3_VHT4SS2 = 100, ++ WL_RATE_2X3_VHT5SS2 = 101, ++ WL_RATE_2X3_VHT6SS2 = 102, ++ WL_RATE_2X3_VHT7SS2 = 103, ++ WL_RATE_2X3_VHT8SS2 = 104, ++ WL_RATE_2X3_VHT9SS2 = 105, ++ ++ /* 3 Streams */ ++ WL_RATE_3X3_SDM_MCS16 = 106, ++ WL_RATE_3X3_SDM_MCS17 = 107, ++ WL_RATE_3X3_SDM_MCS18 = 108, ++ WL_RATE_3X3_SDM_MCS19 = 109, ++ WL_RATE_3X3_SDM_MCS20 = 110, ++ WL_RATE_3X3_SDM_MCS21 = 111, ++ WL_RATE_3X3_SDM_MCS22 = 112, ++ WL_RATE_3X3_SDM_MCS23 = 113, ++ ++ WL_RATE_3X3_VHT0SS3 = 106, ++ WL_RATE_3X3_VHT1SS3 = 107, ++ WL_RATE_3X3_VHT2SS3 = 108, ++ WL_RATE_3X3_VHT3SS3 = 109, ++ WL_RATE_3X3_VHT4SS3 = 110, ++ WL_RATE_3X3_VHT5SS3 = 111, ++ WL_RATE_3X3_VHT6SS3 = 112, ++ WL_RATE_3X3_VHT7SS3 = 113, ++ WL_RATE_3X3_VHT8SS3 = 114, ++ WL_RATE_3X3_VHT9SS3 = 115, ++ ++ /* Number of rate codes */ ++ WL_NUMRATES = 116 ++} clm_rates_t; ++ ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++#endif /* _bcmwifi_rates_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/dhdioctl.h b/drivers/net/wireless/ap6211/include/dhdioctl.h +new file mode 100755 +index 0000000..6909dc2 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/dhdioctl.h +@@ -0,0 +1,136 @@ ++/* ++ * Definitions for ioctls to access DHD iovars. ++ * Based on wlioctl.h (for Broadcom 802.11abg driver). ++ * (Moves towards generic ioctls for BCM drivers/iovars.) ++ * ++ * Definitions subject to change without notice. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhdioctl.h 354894 2012-09-04 12:34:07Z $ ++ */ ++ ++#ifndef _dhdioctl_h_ ++#define _dhdioctl_h_ ++ ++#include ++ ++ ++/* require default structure packing */ ++#define BWL_DEFAULT_PACKING ++#include ++ ++ ++/* Linux network driver ioctl encoding */ ++typedef struct dhd_ioctl { ++ uint cmd; /* common ioctl definition */ ++ void *buf; /* pointer to user buffer */ ++ uint len; /* length of user buffer */ ++ bool set; /* get or set request (optional) */ ++ uint used; /* bytes read or written (optional) */ ++ uint needed; /* bytes needed (optional) */ ++ uint driver; /* to identify target driver */ ++} dhd_ioctl_t; ++ ++/* Underlying BUS definition */ ++enum { ++ BUS_TYPE_USB = 0, /* for USB dongles */ ++ BUS_TYPE_SDIO /* for SDIO dongles */ ++}; ++ ++/* per-driver magic numbers */ ++#define DHD_IOCTL_MAGIC 0x00444944 ++ ++/* bump this number if you change the ioctl interface */ ++#define DHD_IOCTL_VERSION 1 ++ ++#define DHD_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ ++#define DHD_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ ++ ++/* common ioctl definitions */ ++#define DHD_GET_MAGIC 0 ++#define DHD_GET_VERSION 1 ++#define DHD_GET_VAR 2 ++#define DHD_SET_VAR 3 ++ ++/* message levels */ ++#define DHD_ERROR_VAL 0x0001 ++#define DHD_TRACE_VAL 0x0002 ++#define DHD_INFO_VAL 0x0004 ++#define DHD_DATA_VAL 0x0008 ++#define DHD_CTL_VAL 0x0010 ++#define DHD_TIMER_VAL 0x0020 ++#define DHD_HDRS_VAL 0x0040 ++#define DHD_BYTES_VAL 0x0080 ++#define DHD_INTR_VAL 0x0100 ++#define DHD_LOG_VAL 0x0200 ++#define DHD_GLOM_VAL 0x0400 ++#define DHD_EVENT_VAL 0x0800 ++#define DHD_BTA_VAL 0x1000 ++#if 0 && (NDISVER >= 0x0630) && 1 ++#define DHD_SCAN_VAL 0x2000 ++#else ++#define DHD_ISCAN_VAL 0x2000 ++#endif ++#define DHD_ARPOE_VAL 0x4000 ++#define DHD_REORDER_VAL 0x8000 ++#define DHD_IW_VAL 0x10000 ++#define DHD_CFG_VAL 0x20000 ++ ++#ifdef SDTEST ++/* For pktgen iovar */ ++typedef struct dhd_pktgen { ++ uint version; /* To allow structure change tracking */ ++ uint freq; /* Max ticks between tx/rx attempts */ ++ uint count; /* Test packets to send/rcv each attempt */ ++ uint print; /* Print counts every attempts */ ++ uint total; /* Total packets (or bursts) */ ++ uint minlen; /* Minimum length of packets to send */ ++ uint maxlen; /* Maximum length of packets to send */ ++ uint numsent; /* Count of test packets sent */ ++ uint numrcvd; /* Count of test packets received */ ++ uint numfail; /* Count of test send failures */ ++ uint mode; /* Test mode (type of test packets) */ ++ uint stop; /* Stop after this many tx failures */ ++} dhd_pktgen_t; ++ ++/* Version in case structure changes */ ++#define DHD_PKTGEN_VERSION 2 ++ ++/* Type of test packets to use */ ++#define DHD_PKTGEN_ECHO 1 /* Send echo requests */ ++#define DHD_PKTGEN_SEND 2 /* Send discard packets */ ++#define DHD_PKTGEN_RXBURST 3 /* Request dongle send N packets */ ++#define DHD_PKTGEN_RECV 4 /* Continuous rx from continuous tx dongle */ ++#endif /* SDTEST */ ++ ++/* Enter idle immediately (no timeout) */ ++#define DHD_IDLE_IMMEDIATE (-1) ++ ++/* Values for idleclock iovar: other values are the sd_divisor to use when idle */ ++#define DHD_IDLE_ACTIVE 0 /* Do not request any SD clock change when idle */ ++#define DHD_IDLE_STOP (-1) /* Request SD clock be stopped (and use SD1 mode) */ ++ ++ ++/* require default structure packing */ ++#include ++ ++#endif /* _dhdioctl_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/epivers.h b/drivers/net/wireless/ap6211/include/epivers.h +new file mode 100755 +index 0000000..cff9ebd +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/epivers.h +@@ -0,0 +1,56 @@ ++/* ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: epivers.h.in,v 13.33 2010-09-08 22:08:53 csm Exp $ ++ * ++*/ ++ ++#ifndef _epivers_h_ ++#define _epivers_h_ ++ ++#define EPI_MAJOR_VERSION 1 ++ ++#define EPI_MINOR_VERSION 28 ++ ++#define EPI_RC_NUMBER 23 ++ ++#define EPI_INCREMENTAL_NUMBER 0 ++ ++#define EPI_BUILD_NUMBER 0 ++ ++#define EPI_VERSION 1, 28, 23, 0 ++ ++#define EPI_VERSION_NUM 0x011c1700 ++ ++#define EPI_VERSION_DEV 1.28.23 ++ ++/* Driver Version String, ASCII, 32 chars max */ ++#ifdef BCMINTERNAL ++#define EPI_VERSION_STR "1.28.23.3 (r BCMINT)" ++#else ++#ifdef WLTEST ++#define EPI_VERSION_STR "1.28.23.3 (r WLTEST)" ++#else ++#define EPI_VERSION_STR "1.28.23.3 (r)" ++#endif ++#endif /* BCMINTERNAL */ ++ ++#endif /* _epivers_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/hndpmu.h b/drivers/net/wireless/ap6211/include/hndpmu.h +new file mode 100755 +index 0000000..c41def6 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/hndpmu.h +@@ -0,0 +1,36 @@ ++/* ++ * HND SiliconBackplane PMU support. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: hndpmu.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _hndpmu_h_ ++#define _hndpmu_h_ ++ ++ ++extern void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on); ++extern void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength); ++ ++extern void si_pmu_minresmask_htavail_set(si_t *sih, osl_t *osh, bool set_clear); ++ ++#endif /* _hndpmu_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/hndrte_armtrap.h b/drivers/net/wireless/ap6211/include/hndrte_armtrap.h +new file mode 100755 +index 0000000..90d9799 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/hndrte_armtrap.h +@@ -0,0 +1,88 @@ ++/* ++ * HNDRTE arm trap handling. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: hndrte_armtrap.h 261365 2011-05-24 20:42:23Z $ ++ */ ++ ++#ifndef _hndrte_armtrap_h ++#define _hndrte_armtrap_h ++ ++ ++/* ARM trap handling */ ++ ++/* Trap types defined by ARM (see arminc.h) */ ++ ++/* Trap locations in lo memory */ ++#define TRAP_STRIDE 4 ++#define FIRST_TRAP TR_RST ++#define LAST_TRAP (TR_FIQ * TRAP_STRIDE) ++ ++#if defined(__ARM_ARCH_4T__) ++#define MAX_TRAP_TYPE (TR_FIQ + 1) ++#elif defined(__ARM_ARCH_7M__) ++#define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS) ++#endif /* __ARM_ARCH_7M__ */ ++ ++/* The trap structure is defined here as offsets for assembly */ ++#define TR_TYPE 0x00 ++#define TR_EPC 0x04 ++#define TR_CPSR 0x08 ++#define TR_SPSR 0x0c ++#define TR_REGS 0x10 ++#define TR_REG(n) (TR_REGS + (n) * 4) ++#define TR_SP TR_REG(13) ++#define TR_LR TR_REG(14) ++#define TR_PC TR_REG(15) ++ ++#define TRAP_T_SIZE 80 ++ ++#ifndef _LANGUAGE_ASSEMBLY ++ ++#include ++ ++typedef struct _trap_struct { ++ uint32 type; ++ uint32 epc; ++ uint32 cpsr; ++ uint32 spsr; ++ uint32 r0; /* a1 */ ++ uint32 r1; /* a2 */ ++ uint32 r2; /* a3 */ ++ uint32 r3; /* a4 */ ++ uint32 r4; /* v1 */ ++ uint32 r5; /* v2 */ ++ uint32 r6; /* v3 */ ++ uint32 r7; /* v4 */ ++ uint32 r8; /* v5 */ ++ uint32 r9; /* sb/v6 */ ++ uint32 r10; /* sl/v7 */ ++ uint32 r11; /* fp/v8 */ ++ uint32 r12; /* ip */ ++ uint32 r13; /* sp */ ++ uint32 r14; /* lr */ ++ uint32 pc; /* r15 */ ++} trap_t; ++ ++#endif /* !_LANGUAGE_ASSEMBLY */ ++ ++#endif /* _hndrte_armtrap_h */ +diff --git a/drivers/net/wireless/ap6211/include/hndrte_cons.h b/drivers/net/wireless/ap6211/include/hndrte_cons.h +new file mode 100755 +index 0000000..57abbbd +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/hndrte_cons.h +@@ -0,0 +1,67 @@ ++/* ++ * Console support for hndrte. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: hndrte_cons.h 300516 2011-12-04 17:39:44Z $ ++ */ ++#ifndef _HNDRTE_CONS_H ++#define _HNDRTE_CONS_H ++ ++#include ++ ++#define CBUF_LEN (128) ++ ++#define LOG_BUF_LEN 1024 ++ ++typedef struct { ++ uint32 buf; /* Can't be pointer on (64-bit) hosts */ ++ uint buf_size; ++ uint idx; ++ char *_buf_compat; /* redundant pointer for backward compat. */ ++} hndrte_log_t; ++ ++typedef struct { ++ /* Virtual UART ++ * When there is no UART (e.g. Quickturn), the host should write a complete ++ * input line directly into cbuf and then write the length into vcons_in. ++ * This may also be used when there is a real UART (at risk of conflicting with ++ * the real UART). vcons_out is currently unused. ++ */ ++ volatile uint vcons_in; ++ volatile uint vcons_out; ++ ++ /* Output (logging) buffer ++ * Console output is written to a ring buffer log_buf at index log_idx. ++ * The host may read the output when it sees log_idx advance. ++ * Output will be lost if the output wraps around faster than the host polls. ++ */ ++ hndrte_log_t log; ++ ++ /* Console input line buffer ++ * Characters are read one at a time into cbuf until is received, then ++ * the buffer is processed as a command line. Also used for virtual UART. ++ */ ++ uint cbuf_idx; ++ char cbuf[CBUF_LEN]; ++} hndrte_cons_t; ++ ++#endif /* _HNDRTE_CONS_H */ +diff --git a/drivers/net/wireless/ap6211/include/hndsoc.h b/drivers/net/wireless/ap6211/include/hndsoc.h +new file mode 100755 +index 0000000..66640c3 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/hndsoc.h +@@ -0,0 +1,235 @@ ++/* ++ * Broadcom HND chip & on-chip-interconnect-related definitions. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: hndsoc.h 309193 2012-01-19 00:03:57Z $ ++ */ ++ ++#ifndef _HNDSOC_H ++#define _HNDSOC_H ++ ++/* Include the soci specific files */ ++#include ++#include ++ ++/* ++ * SOC Interconnect Address Map. ++ * All regions may not exist on all chips. ++ */ ++#define SI_SDRAM_BASE 0x00000000 /* Physical SDRAM */ ++#define SI_PCI_MEM 0x08000000 /* Host Mode sb2pcitranslation0 (64 MB) */ ++#define SI_PCI_MEM_SZ (64 * 1024 * 1024) ++#define SI_PCI_CFG 0x0c000000 /* Host Mode sb2pcitranslation1 (64 MB) */ ++#define SI_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */ ++#define SI_SDRAM_R2 0x80000000 /* Region 2 for sdram (512 MB) */ ++ ++#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ ++ ++#define SI_WRAP_BASE 0x18100000 /* Wrapper space base */ ++#define SI_CORE_SIZE 0x1000 /* each core gets 4Kbytes for registers */ ++#define SI_MAXCORES 16 /* Max cores (this is arbitrary, for software ++ * convenience and could be changed if we ++ * make any larger chips ++ */ ++ ++#define SI_FASTRAM 0x19000000 /* On-chip RAM on chips that also have DDR */ ++#define SI_FASTRAM_SWAPPED 0x19800000 ++ ++#define SI_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */ ++#define SI_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */ ++#define SI_ARMCM3_ROM 0x1e000000 /* ARM Cortex-M3 ROM */ ++#define SI_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */ ++#define SI_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */ ++#define SI_ARM7S_ROM 0x20000000 /* ARM7TDMI-S ROM */ ++#define SI_ARMCR4_ROM 0x000f0000 /* ARM Cortex-R4 ROM */ ++#define SI_ARMCM3_SRAM2 0x60000000 /* ARM Cortex-M3 SRAM Region 2 */ ++#define SI_ARM7S_SRAM2 0x80000000 /* ARM7TDMI-S SRAM Region 2 */ ++#define SI_ARM_FLASH1 0xffff0000 /* ARM Flash Region 1 */ ++#define SI_ARM_FLASH1_SZ 0x00010000 /* ARM Size of Flash Region 1 */ ++ ++#define SI_PCI_DMA 0x40000000 /* Client Mode sb2pcitranslation2 (1 GB) */ ++#define SI_PCI_DMA2 0x80000000 /* Client Mode sb2pcitranslation2 (1 GB) */ ++#define SI_PCI_DMA_SZ 0x40000000 /* Client Mode sb2pcitranslation2 size in bytes */ ++#define SI_PCIE_DMA_L32 0x00000000 /* PCIE Client Mode sb2pcitranslation2 ++ * (2 ZettaBytes), low 32 bits ++ */ ++#define SI_PCIE_DMA_H32 0x80000000 /* PCIE Client Mode sb2pcitranslation2 ++ * (2 ZettaBytes), high 32 bits ++ */ ++ ++/* core codes */ ++#define NODEV_CORE_ID 0x700 /* Invalid coreid */ ++#define CC_CORE_ID 0x800 /* chipcommon core */ ++#define ILINE20_CORE_ID 0x801 /* iline20 core */ ++#define SRAM_CORE_ID 0x802 /* sram core */ ++#define SDRAM_CORE_ID 0x803 /* sdram core */ ++#define PCI_CORE_ID 0x804 /* pci core */ ++#define MIPS_CORE_ID 0x805 /* mips core */ ++#define ENET_CORE_ID 0x806 /* enet mac core */ ++#define CODEC_CORE_ID 0x807 /* v90 codec core */ ++#define USB_CORE_ID 0x808 /* usb 1.1 host/device core */ ++#define ADSL_CORE_ID 0x809 /* ADSL core */ ++#define ILINE100_CORE_ID 0x80a /* iline100 core */ ++#define IPSEC_CORE_ID 0x80b /* ipsec core */ ++#define UTOPIA_CORE_ID 0x80c /* utopia core */ ++#define PCMCIA_CORE_ID 0x80d /* pcmcia core */ ++#define SOCRAM_CORE_ID 0x80e /* internal memory core */ ++#define MEMC_CORE_ID 0x80f /* memc sdram core */ ++#define OFDM_CORE_ID 0x810 /* OFDM phy core */ ++#define EXTIF_CORE_ID 0x811 /* external interface core */ ++#define D11_CORE_ID 0x812 /* 802.11 MAC core */ ++#define APHY_CORE_ID 0x813 /* 802.11a phy core */ ++#define BPHY_CORE_ID 0x814 /* 802.11b phy core */ ++#define GPHY_CORE_ID 0x815 /* 802.11g phy core */ ++#define MIPS33_CORE_ID 0x816 /* mips3302 core */ ++#define USB11H_CORE_ID 0x817 /* usb 1.1 host core */ ++#define USB11D_CORE_ID 0x818 /* usb 1.1 device core */ ++#define USB20H_CORE_ID 0x819 /* usb 2.0 host core */ ++#define USB20D_CORE_ID 0x81a /* usb 2.0 device core */ ++#define SDIOH_CORE_ID 0x81b /* sdio host core */ ++#define ROBO_CORE_ID 0x81c /* roboswitch core */ ++#define ATA100_CORE_ID 0x81d /* parallel ATA core */ ++#define SATAXOR_CORE_ID 0x81e /* serial ATA & XOR DMA core */ ++#define GIGETH_CORE_ID 0x81f /* gigabit ethernet core */ ++#define PCIE_CORE_ID 0x820 /* pci express core */ ++#define NPHY_CORE_ID 0x821 /* 802.11n 2x2 phy core */ ++#define SRAMC_CORE_ID 0x822 /* SRAM controller core */ ++#define MINIMAC_CORE_ID 0x823 /* MINI MAC/phy core */ ++#define ARM11_CORE_ID 0x824 /* ARM 1176 core */ ++#define ARM7S_CORE_ID 0x825 /* ARM7tdmi-s core */ ++#define LPPHY_CORE_ID 0x826 /* 802.11a/b/g phy core */ ++#define PMU_CORE_ID 0x827 /* PMU core */ ++#define SSNPHY_CORE_ID 0x828 /* 802.11n single-stream phy core */ ++#define SDIOD_CORE_ID 0x829 /* SDIO device core */ ++#define ARMCM3_CORE_ID 0x82a /* ARM Cortex M3 core */ ++#define HTPHY_CORE_ID 0x82b /* 802.11n 4x4 phy core */ ++#define MIPS74K_CORE_ID 0x82c /* mips 74k core */ ++#define GMAC_CORE_ID 0x82d /* Gigabit MAC core */ ++#define DMEMC_CORE_ID 0x82e /* DDR1/2 memory controller core */ ++#define PCIERC_CORE_ID 0x82f /* PCIE Root Complex core */ ++#define OCP_CORE_ID 0x830 /* OCP2OCP bridge core */ ++#define SC_CORE_ID 0x831 /* shared common core */ ++#define AHB_CORE_ID 0x832 /* OCP2AHB bridge core */ ++#define SPIH_CORE_ID 0x833 /* SPI host core */ ++#define I2S_CORE_ID 0x834 /* I2S core */ ++#define DMEMS_CORE_ID 0x835 /* SDR/DDR1 memory controller core */ ++#define DEF_SHIM_COMP 0x837 /* SHIM component in ubus/6362 */ ++ ++#define ACPHY_CORE_ID 0x83b /* Dot11 ACPHY */ ++#define PCIE2_CORE_ID 0x83c /* pci express Gen2 core */ ++#define USB30D_CORE_ID 0x83d /* usb 3.0 device core */ ++#define ARMCR4_CORE_ID 0x83e /* ARM CR4 CPU */ ++#define APB_BRIDGE_CORE_ID 0x135 /* APB bridge core ID */ ++#define AXI_CORE_ID 0x301 /* AXI/GPV core ID */ ++#define EROM_CORE_ID 0x366 /* EROM core ID */ ++#define OOB_ROUTER_CORE_ID 0x367 /* OOB router core ID */ ++#define DEF_AI_COMP 0xfff /* Default component, in ai chips it maps all ++ * unused address ranges ++ */ ++ ++#define CC_4706_CORE_ID 0x500 /* chipcommon core */ ++#define SOCRAM_4706_CORE_ID 0x50e /* internal memory core */ ++#define GMAC_COMMON_4706_CORE_ID 0x5dc /* Gigabit MAC core */ ++#define GMAC_4706_CORE_ID 0x52d /* Gigabit MAC core */ ++#define AMEMC_CORE_ID 0x52e /* DDR1/2 memory controller core */ ++#define ALTA_CORE_ID 0x534 /* I2S core */ ++#define DDR23_PHY_CORE_ID 0x5dd ++ ++#define SI_PCI1_MEM 0x40000000 /* Host Mode sb2pcitranslation0 (64 MB) */ ++#define SI_PCI1_CFG 0x44000000 /* Host Mode sb2pcitranslation1 (64 MB) */ ++#define SI_PCIE1_DMA_H32 0xc0000000 /* PCIE Client Mode sb2pcitranslation2 ++ * (2 ZettaBytes), high 32 bits ++ */ ++#define CC_4706B0_CORE_REV 0x8000001f /* chipcommon core */ ++#define SOCRAM_4706B0_CORE_REV 0x80000005 /* internal memory core */ ++#define GMAC_4706B0_CORE_REV 0x80000000 /* Gigabit MAC core */ ++ ++/* There are TWO constants on all HND chips: SI_ENUM_BASE above, ++ * and chipcommon being the first core: ++ */ ++#define SI_CC_IDX 0 ++ ++/* SOC Interconnect types (aka chip types) */ ++#define SOCI_SB 0 ++#define SOCI_AI 1 ++#define SOCI_UBUS 2 ++ ++/* Common core control flags */ ++#define SICF_BIST_EN 0x8000 ++#define SICF_PME_EN 0x4000 ++#define SICF_CORE_BITS 0x3ffc ++#define SICF_FGC 0x0002 ++#define SICF_CLOCK_EN 0x0001 ++ ++/* Common core status flags */ ++#define SISF_BIST_DONE 0x8000 ++#define SISF_BIST_ERROR 0x4000 ++#define SISF_GATED_CLK 0x2000 ++#define SISF_DMA64 0x1000 ++#define SISF_CORE_BITS 0x0fff ++ ++/* A register that is common to all cores to ++ * communicate w/PMU regarding clock control. ++ */ ++#define SI_CLK_CTL_ST 0x1e0 /* clock control and status */ ++ ++/* clk_ctl_st register */ ++#define CCS_FORCEALP 0x00000001 /* force ALP request */ ++#define CCS_FORCEHT 0x00000002 /* force HT request */ ++#define CCS_FORCEILP 0x00000004 /* force ILP request */ ++#define CCS_ALPAREQ 0x00000008 /* ALP Avail Request */ ++#define CCS_HTAREQ 0x00000010 /* HT Avail Request */ ++#define CCS_FORCEHWREQOFF 0x00000020 /* Force HW Clock Request Off */ ++#define CCS_HQCLKREQ 0x00000040 /* HQ Clock Required */ ++#define CCS_USBCLKREQ 0x00000100 /* USB Clock Req */ ++#define CCS_ERSRC_REQ_MASK 0x00000700 /* external resource requests */ ++#define CCS_ERSRC_REQ_SHIFT 8 ++#define CCS_ALPAVAIL 0x00010000 /* ALP is available */ ++#define CCS_HTAVAIL 0x00020000 /* HT is available */ ++#define CCS_BP_ON_APL 0x00040000 /* RO: Backplane is running on ALP clock */ ++#define CCS_BP_ON_HT 0x00080000 /* RO: Backplane is running on HT clock */ ++#define CCS_ERSRC_STS_MASK 0x07000000 /* external resource status */ ++#define CCS_ERSRC_STS_SHIFT 24 ++ ++#define CCS0_HTAVAIL 0x00010000 /* HT avail in chipc and pcmcia on 4328a0 */ ++#define CCS0_ALPAVAIL 0x00020000 /* ALP avail in chipc and pcmcia on 4328a0 */ ++ ++/* Not really related to SOC Interconnect, but a couple of software ++ * conventions for the use the flash space: ++ */ ++ ++/* Minumum amount of flash we support */ ++#define FLASH_MIN 0x00020000 /* Minimum flash size */ ++ ++/* A boot/binary may have an embedded block that describes its size */ ++#define BISZ_OFFSET 0x3e0 /* At this offset into the binary */ ++#define BISZ_MAGIC 0x4249535a /* Marked with this value: 'BISZ' */ ++#define BISZ_MAGIC_IDX 0 /* Word 0: magic */ ++#define BISZ_TXTST_IDX 1 /* 1: text start */ ++#define BISZ_TXTEND_IDX 2 /* 2: text end */ ++#define BISZ_DATAST_IDX 3 /* 3: data start */ ++#define BISZ_DATAEND_IDX 4 /* 4: data end */ ++#define BISZ_BSSST_IDX 5 /* 5: bss start */ ++#define BISZ_BSSEND_IDX 6 /* 6: bss end */ ++#define BISZ_SIZE 7 /* descriptor size in 32-bit integers */ ++ ++#endif /* _HNDSOC_H */ +diff --git a/drivers/net/wireless/ap6211/include/linux_osl.h b/drivers/net/wireless/ap6211/include/linux_osl.h +new file mode 100755 +index 0000000..ca28f6b +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/linux_osl.h +@@ -0,0 +1,430 @@ ++/* ++ * Linux OS Independent Layer ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: linux_osl.h 354452 2012-08-31 04:59:17Z $ ++ */ ++ ++#ifndef _linux_osl_h_ ++#define _linux_osl_h_ ++ ++#include ++ ++/* Linux Kernel: File Operations: start */ ++extern void * osl_os_open_image(char * filename); ++extern int osl_os_get_image_block(char * buf, int len, void * image); ++extern void osl_os_close_image(void * image); ++extern int osl_os_image_size(void *image); ++/* Linux Kernel: File Operations: end */ ++ ++#ifdef BCMDRIVER ++ ++/* OSL initialization */ ++extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag); ++extern void osl_detach(osl_t *osh); ++ ++/* Global ASSERT type */ ++extern uint32 g_assert_type; ++ ++/* ASSERT */ ++#if defined(BCMASSERT_LOG) ++ #define ASSERT(exp) \ ++ do { if (!(exp)) osl_assert(#exp, __FILE__, __LINE__); } while (0) ++extern void osl_assert(const char *exp, const char *file, int line); ++#else ++ #ifdef __GNUC__ ++ #define GCC_VERSION \ ++ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) ++ #if GCC_VERSION > 30100 ++ #define ASSERT(exp) do {} while (0) ++ #else ++ /* ASSERT could cause segmentation fault on GCC3.1, use empty instead */ ++ #define ASSERT(exp) ++ #endif /* GCC_VERSION > 30100 */ ++ #endif /* __GNUC__ */ ++#endif ++ ++/* microsecond delay */ ++#define OSL_DELAY(usec) osl_delay(usec) ++extern void osl_delay(uint usec); ++ ++#define OSL_PCMCIA_READ_ATTR(osh, offset, buf, size) \ ++ osl_pcmcia_read_attr((osh), (offset), (buf), (size)) ++#define OSL_PCMCIA_WRITE_ATTR(osh, offset, buf, size) \ ++ osl_pcmcia_write_attr((osh), (offset), (buf), (size)) ++extern void osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size); ++extern void osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size); ++ ++/* PCI configuration space access macros */ ++#define OSL_PCI_READ_CONFIG(osh, offset, size) \ ++ osl_pci_read_config((osh), (offset), (size)) ++#define OSL_PCI_WRITE_CONFIG(osh, offset, size, val) \ ++ osl_pci_write_config((osh), (offset), (size), (val)) ++extern uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size); ++extern void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val); ++ ++/* PCI device bus # and slot # */ ++#define OSL_PCI_BUS(osh) osl_pci_bus(osh) ++#define OSL_PCI_SLOT(osh) osl_pci_slot(osh) ++extern uint osl_pci_bus(osl_t *osh); ++extern uint osl_pci_slot(osl_t *osh); ++extern struct pci_dev *osl_pci_device(osl_t *osh); ++ ++/* Pkttag flag should be part of public information */ ++typedef struct { ++ bool pkttag; ++ uint pktalloced; /* Number of allocated packet buffers */ ++ bool mmbus; /* Bus supports memory-mapped register accesses */ ++ pktfree_cb_fn_t tx_fn; /* Callback function for PKTFREE */ ++ void *tx_ctx; /* Context to the callback function */ ++ void *unused[3]; ++} osl_pubinfo_t; ++ ++#define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \ ++ do { \ ++ ((osl_pubinfo_t*)osh)->tx_fn = _tx_fn; \ ++ ((osl_pubinfo_t*)osh)->tx_ctx = _tx_ctx; \ ++ } while (0) ++ ++ ++/* host/bus architecture-specific byte swap */ ++#define BUS_SWAP32(v) (v) ++ ++ #define MALLOC(osh, size) osl_malloc((osh), (size)) ++ #define MFREE(osh, addr, size) osl_mfree((osh), (addr), (size)) ++ #define MALLOCED(osh) osl_malloced((osh)) ++ extern void *osl_malloc(osl_t *osh, uint size); ++ extern void osl_mfree(osl_t *osh, void *addr, uint size); ++ extern uint osl_malloced(osl_t *osh); ++ ++#define NATIVE_MALLOC(osh, size) kmalloc(size, GFP_ATOMIC) ++#define NATIVE_MFREE(osh, addr, size) kfree(addr) ++ ++#define MALLOC_FAILED(osh) osl_malloc_failed((osh)) ++extern uint osl_malloc_failed(osl_t *osh); ++ ++/* allocate/free shared (dma-able) consistent memory */ ++#define DMA_CONSISTENT_ALIGN osl_dma_consistent_align() ++#define DMA_ALLOC_CONSISTENT(osh, size, align, tot, pap, dmah) \ ++ osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) ++#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \ ++ osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) ++extern uint osl_dma_consistent_align(void); ++extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align, uint *tot, ulong *pap); ++extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa); ++ ++/* map/unmap direction */ ++#define DMA_TX 1 /* TX direction for DMA */ ++#define DMA_RX 2 /* RX direction for DMA */ ++ ++/* map/unmap shared (dma-able) memory */ ++#define DMA_UNMAP(osh, pa, size, direction, p, dmah) \ ++ osl_dma_unmap((osh), (pa), (size), (direction)) ++extern uint osl_dma_map(osl_t *osh, void *va, uint size, int direction); ++extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); ++ ++/* API for DMA addressing capability */ ++#define OSL_DMADDRWIDTH(osh, addrwidth) do {} while (0) ++ ++/* register access macros */ ++ #include ++ #define OSL_WRITE_REG(osh, r, v) (bcmsdh_reg_write(NULL, (uintptr)(r), sizeof(*(r)), (v))) ++ #define OSL_READ_REG(osh, r) (bcmsdh_reg_read(NULL, (uintptr)(r), sizeof(*(r)))) ++ ++ #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) if (((osl_pubinfo_t*)(osh))->mmbus) \ ++ mmap_op else bus_op ++ #define SELECT_BUS_READ(osh, mmap_op, bus_op) (((osl_pubinfo_t*)(osh))->mmbus) ? \ ++ mmap_op : bus_op ++ ++#define OSL_ERROR(bcmerror) osl_error(bcmerror) ++extern int osl_error(int bcmerror); ++ ++/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */ ++#define PKTBUFSZ 2048 /* largest reasonable packet buffer, driver uses for ethernet MTU */ ++ ++/* ++ * BINOSL selects the slightly slower function-call-based binary compatible osl. ++ * Macros expand to calls to functions defined in linux_osl.c . ++ */ ++#include /* use current 2.4.x calling conventions */ ++#include /* for vsn/printf's */ ++#include /* for mem*, str* */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) ++#define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies)) ++#else ++#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ)) ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) */ ++#define printf(fmt, args...) pr_info(fmt , ## args) ++#include /* for vsn/printf's */ ++#include /* for mem*, str* */ ++/* bcopy's: Linux kernel doesn't provide these (anymore) */ ++#define bcopy(src, dst, len) memcpy((dst), (src), (len)) ++#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) ++#define bzero(b, len) memset((b), '\0', (len)) ++ ++/* register access macros */ ++ ++#define R_REG(osh, r) (\ ++ SELECT_BUS_READ(osh, \ ++ ({ \ ++ __typeof(*(r)) __osl_v; \ ++ BCM_REFERENCE(osh); \ ++ switch (sizeof(*(r))) { \ ++ case sizeof(uint8): __osl_v = \ ++ readb((volatile uint8*)(r)); break; \ ++ case sizeof(uint16): __osl_v = \ ++ readw((volatile uint16*)(r)); break; \ ++ case sizeof(uint32): __osl_v = \ ++ readl((volatile uint32*)(r)); break; \ ++ } \ ++ __osl_v; \ ++ }), \ ++ OSL_READ_REG(osh, r)) \ ++) ++ ++#define W_REG(osh, r, v) do { \ ++ BCM_REFERENCE(osh); \ ++ SELECT_BUS_WRITE(osh, \ ++ switch (sizeof(*(r))) { \ ++ case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \ ++ case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \ ++ case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \ ++ }, \ ++ (OSL_WRITE_REG(osh, r, v))); \ ++ } while (0) ++ ++#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) ++#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) ++ ++/* bcopy, bcmp, and bzero functions */ ++#define bcopy(src, dst, len) memcpy((dst), (src), (len)) ++#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) ++#define bzero(b, len) memset((b), '\0', (len)) ++ ++/* uncached/cached virtual address */ ++#define OSL_UNCACHED(va) ((void *)va) ++#define OSL_CACHED(va) ((void *)va) ++ ++#define OSL_PREF_RANGE_LD(va, sz) ++#define OSL_PREF_RANGE_ST(va, sz) ++ ++/* get processor cycle count */ ++#if defined(__i386__) ++#define OSL_GETCYCLES(x) rdtscl((x)) ++#else ++#define OSL_GETCYCLES(x) ((x) = 0) ++#endif ++ ++/* dereference an address that may cause a bus exception */ ++#define BUSPROBE(val, addr) ({ (val) = R_REG(NULL, (addr)); 0; }) ++ ++/* map/unmap physical to virtual I/O */ ++#if !defined(CONFIG_MMC_MSM7X00A) ++#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size)) ++#else ++#define REG_MAP(pa, size) (void *)(0) ++#endif /* !defined(CONFIG_MMC_MSM7X00A */ ++#define REG_UNMAP(va) iounmap((va)) ++ ++/* shared (dma-able) memory access macros */ ++#define R_SM(r) *(r) ++#define W_SM(r, v) (*(r) = (v)) ++#define BZERO_SM(r, len) memset((r), '\0', (len)) ++ ++/* Because the non BINOSL implemenation of the PKT OSL routines are macros (for ++ * performance reasons), we need the Linux headers. ++ */ ++#include /* use current 2.4.x calling conventions */ ++ ++/* packet primitives */ ++#define PKTGET(osh, len, send) osl_pktget((osh), (len)) ++#define PKTDUP(osh, skb) osl_pktdup((osh), (skb)) ++#define PKTLIST_DUMP(osh, buf) ++#define PKTDBG_TRACE(osh, pkt, bit) ++#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++#define PKTGET_STATIC(osh, len, send) osl_pktget_static((osh), (len)) ++#define PKTFREE_STATIC(osh, skb, send) osl_pktfree_static((osh), (skb), (send)) ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++#define PKTDATA(osh, skb) (((struct sk_buff*)(skb))->data) ++#define PKTLEN(osh, skb) (((struct sk_buff*)(skb))->len) ++#define PKTHEADROOM(osh, skb) (PKTDATA(osh, skb)-(((struct sk_buff*)(skb))->head)) ++#define PKTTAILROOM(osh, skb) ((((struct sk_buff*)(skb))->end)-(((struct sk_buff*)(skb))->tail)) ++#define PKTNEXT(osh, skb) (((struct sk_buff*)(skb))->next) ++#define PKTSETNEXT(osh, skb, x) (((struct sk_buff*)(skb))->next = (struct sk_buff*)(x)) ++#define PKTSETLEN(osh, skb, len) __skb_trim((struct sk_buff*)(skb), (len)) ++#define PKTPUSH(osh, skb, bytes) skb_push((struct sk_buff*)(skb), (bytes)) ++#define PKTPULL(osh, skb, bytes) skb_pull((struct sk_buff*)(skb), (bytes)) ++#define PKTTAG(skb) ((void*)(((struct sk_buff*)(skb))->cb)) ++#define PKTALLOCED(osh) ((osl_pubinfo_t *)(osh))->pktalloced ++#define PKTSETPOOL(osh, skb, x, y) do {} while (0) ++#define PKTPOOL(osh, skb) FALSE ++#define PKTSHRINK(osh, m) (m) ++ ++#ifdef CTFPOOL ++#define CTFPOOL_REFILL_THRESH 3 ++typedef struct ctfpool { ++ void *head; ++ spinlock_t lock; ++ uint max_obj; ++ uint curr_obj; ++ uint obj_size; ++ uint refills; ++ uint fast_allocs; ++ uint fast_frees; ++ uint slow_allocs; ++} ctfpool_t; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) ++#define FASTBUF (1 << 16) ++#define CTFBUF (1 << 17) ++#define PKTSETFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) |= FASTBUF) ++#define PKTCLRFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) &= (~FASTBUF)) ++#define PKTSETCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) |= CTFBUF) ++#define PKTCLRCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) &= (~CTFBUF)) ++#define PKTISFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) & FASTBUF) ++#define PKTISCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) & CTFBUF) ++#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->mac_len) ++#else ++#define FASTBUF (1 << 0) ++#define CTFBUF (1 << 1) ++#define PKTSETFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) |= FASTBUF) ++#define PKTCLRFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) &= (~FASTBUF)) ++#define PKTSETCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) |= CTFBUF) ++#define PKTCLRCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) &= (~CTFBUF)) ++#define PKTISFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) & FASTBUF) ++#define PKTISCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) & CTFBUF) ++#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->__unused) ++#endif /* 2.6.22 */ ++ ++#define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->sk) ++#define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->sk)->head) ++ ++extern void *osl_ctfpool_add(osl_t *osh); ++extern void osl_ctfpool_replenish(osl_t *osh, uint thresh); ++extern int32 osl_ctfpool_init(osl_t *osh, uint numobj, uint size); ++extern void osl_ctfpool_cleanup(osl_t *osh); ++extern void osl_ctfpool_stats(osl_t *osh, void *b); ++#endif /* CTFPOOL */ ++ ++ ++#ifdef HNDCTF ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) ++#define SKIPCT (1 << 18) ++#define PKTSETSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len |= SKIPCT) ++#define PKTCLRSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len &= (~SKIPCT)) ++#define PKTSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len & SKIPCT) ++#else /* 2.6.22 */ ++#define SKIPCT (1 << 2) ++#define PKTSETSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused |= SKIPCT) ++#define PKTCLRSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused &= (~SKIPCT)) ++#define PKTSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused & SKIPCT) ++#endif /* 2.6.22 */ ++#else /* HNDCTF */ ++#define PKTSETSKIPCT(osh, skb) ++#define PKTCLRSKIPCT(osh, skb) ++#define PKTSKIPCT(osh, skb) ++#endif /* HNDCTF */ ++ ++extern void osl_pktfree(osl_t *osh, void *skb, bool send); ++extern void *osl_pktget_static(osl_t *osh, uint len); ++extern void osl_pktfree_static(osl_t *osh, void *skb, bool send); ++ ++extern void *osl_pkt_frmnative(osl_t *osh, void *skb); ++extern void *osl_pktget(osl_t *osh, uint len); ++extern void *osl_pktdup(osl_t *osh, void *skb); ++extern struct sk_buff *osl_pkt_tonative(osl_t *osh, void *pkt); ++#define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative(((osl_t *)osh), (struct sk_buff*)(skb)) ++#define PKTTONATIVE(osh, pkt) osl_pkt_tonative((osl_t *)(osh), (pkt)) ++ ++#define PKTLINK(skb) (((struct sk_buff*)(skb))->prev) ++#define PKTSETLINK(skb, x) (((struct sk_buff*)(skb))->prev = (struct sk_buff*)(x)) ++#define PKTPRIO(skb) (((struct sk_buff*)(skb))->priority) ++#define PKTSETPRIO(skb, x) (((struct sk_buff*)(skb))->priority = (x)) ++#define PKTSUMNEEDED(skb) (((struct sk_buff*)(skb))->ip_summed == CHECKSUM_HW) ++#define PKTSETSUMGOOD(skb, x) (((struct sk_buff*)(skb))->ip_summed = \ ++ ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE)) ++/* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because skb->ip_summed is overloaded */ ++#define PKTSHARED(skb) (((struct sk_buff*)(skb))->cloned) ++ ++#define DMA_MAP(osh, va, size, direction, p, dmah) \ ++ osl_dma_map((osh), (va), (size), (direction)) ++ ++#ifdef PKTC ++/* Use 8 bytes of skb tstamp field to store below info */ ++struct chain_node { ++ struct sk_buff *link; ++ unsigned int flags:3, pkts:9, bytes:20; ++}; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) ++#define CHAIN_NODE(skb) ((struct chain_node*)&(((struct sk_buff*)skb)->tstamp)) ++#else ++#define CHAIN_NODE(skb) ((struct chain_node*)&(((struct sk_buff*)skb)->stamp)) ++#endif ++ ++#define PKTCCNT(skb) (CHAIN_NODE(skb)->pkts) ++#define PKTCLEN(skb) (CHAIN_NODE(skb)->bytes) ++#define PKTCFLAGS(skb) (CHAIN_NODE(skb)->flags) ++#define PKTCSETCNT(skb, c) (CHAIN_NODE(skb)->pkts = (c) & ((1 << 9) - 1)) ++#define PKTCSETLEN(skb, l) (CHAIN_NODE(skb)->bytes = (l) & ((1 << 20) - 1)) ++#define PKTCSETFLAG(skb, fb) (CHAIN_NODE(skb)->flags |= (fb)) ++#define PKTCCLRFLAG(skb, fb) (CHAIN_NODE(skb)->flags &= ~(fb)) ++#define PKTCLINK(skb) (CHAIN_NODE(skb)->link) ++#define PKTSETCLINK(skb, x) (CHAIN_NODE(skb)->link = (struct sk_buff*)(x)) ++#define PKTISCHAINED(skb) (PKTCLINK(skb) != NULL) ++#define FOREACH_CHAINED_PKT(skb, nskb) \ ++ for (; (skb) != NULL; (skb) = (nskb)) \ ++ if ((nskb) = PKTCLINK(skb), PKTSETCLINK((skb), NULL), 1) ++#define PKTCFREE(osh, skb, send) \ ++do { \ ++ void *nskb; \ ++ ASSERT((skb) != NULL); \ ++ FOREACH_CHAINED_PKT((skb), nskb) { \ ++ PKTFREE((osh), (skb), (send)); \ ++ } \ ++} while (0) ++#endif /* PKTC */ ++ ++#else /* ! BCMDRIVER */ ++ ++ ++/* ASSERT */ ++ #define ASSERT(exp) do {} while (0) ++ ++/* MALLOC and MFREE */ ++#define MALLOC(o, l) malloc(l) ++#define MFREE(o, p, l) free(p) ++#include ++ ++/* str* and mem* functions */ ++#include ++ ++/* *printf functions */ ++#include ++ ++/* bcopy, bcmp, and bzero */ ++extern void bcopy(const void *src, void *dst, size_t len); ++extern int bcmp(const void *b1, const void *b2, size_t len); ++extern void bzero(void *b, size_t len); ++#endif /* ! BCMDRIVER */ ++ ++#endif /* _linux_osl_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/linuxver.h b/drivers/net/wireless/ap6211/include/linuxver.h +new file mode 100755 +index 0000000..e01b8f0 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/linuxver.h +@@ -0,0 +1,652 @@ ++/* ++ * Linux-specific abstractions to gain some independence from linux kernel versions. ++ * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: linuxver.h 366812 2012-11-05 13:49:32Z $ ++ */ ++ ++#ifndef _linuxver_h_ ++#define _linuxver_h_ ++ ++#include ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++#include ++#else ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) ++#include ++#else ++#include ++#endif ++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ ++#include ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)) ++/* __NO_VERSION__ must be defined for all linkables except one in 2.2 */ ++#ifdef __UNDEF_NO_VERSION__ ++#undef __NO_VERSION__ ++#else ++#define __NO_VERSION__ ++#endif ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) ++#define module_param(_name_, _type_, _perm_) MODULE_PARM(_name_, "i") ++#define module_param_string(_name_, _string_, _size_, _perm_) \ ++ MODULE_PARM(_string_, "c" __MODULE_STRING(_size_)) ++#endif ++ ++/* linux/malloc.h is deprecated, use linux/slab.h instead. */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 9)) ++#include ++#else ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++#include ++#else ++#include ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) ++#undef IP_TOS ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) */ ++#include ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41)) ++#include ++#else ++#include ++#ifndef work_struct ++#define work_struct tq_struct ++#endif ++#ifndef INIT_WORK ++#define INIT_WORK(_work, _func, _data) INIT_TQUEUE((_work), (_func), (_data)) ++#endif ++#ifndef schedule_work ++#define schedule_work(_work) schedule_task((_work)) ++#endif ++#ifndef flush_scheduled_work ++#define flush_scheduled_work() flush_scheduled_tasks() ++#endif ++#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41) */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++#define DAEMONIZE(a) daemonize(a); \ ++ allow_signal(SIGKILL); \ ++ allow_signal(SIGTERM); ++#else /* Linux 2.4 (w/o preemption patch) */ ++#define RAISE_RX_SOFTIRQ() \ ++ cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) ++#define DAEMONIZE(a) daemonize(); \ ++ do { if (a) \ ++ strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a)))); \ ++ } while (0); ++#endif /* LINUX_VERSION_CODE */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) ++#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func) ++#else ++#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func, _work) ++#if !(LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18) && defined(RHEL_MAJOR) && \ ++ (RHEL_MAJOR == 5)) ++/* Exclude RHEL 5 */ ++typedef void (*work_func_t)(void *work); ++#endif ++#endif /* >= 2.6.20 */ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++/* Some distributions have their own 2.6.x compatibility layers */ ++#ifndef IRQ_NONE ++typedef void irqreturn_t; ++#define IRQ_NONE ++#define IRQ_HANDLED ++#define IRQ_RETVAL(x) ++#endif ++#else ++typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs); ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) ++#define IRQF_SHARED SA_SHIRQ ++#endif /* < 2.6.18 */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) ++#ifdef CONFIG_NET_RADIO ++#define CONFIG_WIRELESS_EXT ++#endif ++#endif /* < 2.6.17 */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) ++#define MOD_INC_USE_COUNT ++#define MOD_DEC_USE_COUNT ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) ++#include ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) ++#include ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) ++#include ++#else ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) ++#include ++#endif ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) */ ++ ++ ++ ++#ifndef __exit ++#define __exit ++#endif ++#ifndef __devexit ++#define __devexit ++#endif ++#ifndef __devinit ++#define __devinit __init ++#endif ++#ifndef __devinitdata ++#define __devinitdata ++#endif ++#ifndef __devexit_p ++#define __devexit_p(x) x ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)) ++ ++#define pci_get_drvdata(dev) (dev)->sysdata ++#define pci_set_drvdata(dev, value) (dev)->sysdata = (value) ++ ++/* ++ * New-style (2.4.x) PCI/hot-pluggable PCI/CardBus registration ++ */ ++ ++struct pci_device_id { ++ unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ ++ unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ ++ unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ ++ unsigned long driver_data; /* Data private to the driver */ ++}; ++ ++struct pci_driver { ++ struct list_head node; ++ char *name; ++ const struct pci_device_id *id_table; /* NULL if wants all devices */ ++ int (*probe)(struct pci_dev *dev, ++ const struct pci_device_id *id); /* New device inserted */ ++ void (*remove)(struct pci_dev *dev); /* Device removed (NULL if not a hot-plug ++ * capable driver) ++ */ ++ void (*suspend)(struct pci_dev *dev); /* Device suspended */ ++ void (*resume)(struct pci_dev *dev); /* Device woken up */ ++}; ++ ++#define MODULE_DEVICE_TABLE(type, name) ++#define PCI_ANY_ID (~0) ++ ++/* compatpci.c */ ++#define pci_module_init pci_register_driver ++extern int pci_register_driver(struct pci_driver *drv); ++extern void pci_unregister_driver(struct pci_driver *drv); ++ ++#endif /* PCI registration */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)) ++#define pci_module_init pci_register_driver ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)) ++#ifdef MODULE ++#define module_init(x) int init_module(void) { return x(); } ++#define module_exit(x) void cleanup_module(void) { x(); } ++#else ++#define module_init(x) __initcall(x); ++#define module_exit(x) __exitcall(x); ++#endif ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) ++#define WL_USE_NETDEV_OPS ++#else ++#undef WL_USE_NETDEV_OPS ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) && defined(CONFIG_RFKILL) ++#define WL_CONFIG_RFKILL ++#else ++#undef WL_CONFIG_RFKILL ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 48)) ++#define list_for_each(pos, head) \ ++ for (pos = (head)->next; pos != (head); pos = pos->next) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 13)) ++#define pci_resource_start(dev, bar) ((dev)->base_address[(bar)]) ++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 44)) ++#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 23)) ++#define pci_enable_device(dev) do { } while (0) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14)) ++#define net_device device ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 42)) ++ ++/* ++ * DMA mapping ++ * ++ * See linux/Documentation/DMA-mapping.txt ++ */ ++ ++#ifndef PCI_DMA_TODEVICE ++#define PCI_DMA_TODEVICE 1 ++#define PCI_DMA_FROMDEVICE 2 ++#endif ++ ++typedef u32 dma_addr_t; ++ ++/* Pure 2^n version of get_order */ ++static inline int get_order(unsigned long size) ++{ ++ int order; ++ ++ size = (size-1) >> (PAGE_SHIFT-1); ++ order = -1; ++ do { ++ size >>= 1; ++ order++; ++ } while (size); ++ return order; ++} ++ ++static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, ++ dma_addr_t *dma_handle) ++{ ++ void *ret; ++ int gfp = GFP_ATOMIC | GFP_DMA; ++ ++ ret = (void *)__get_free_pages(gfp, get_order(size)); ++ ++ if (ret != NULL) { ++ memset(ret, 0, size); ++ *dma_handle = virt_to_bus(ret); ++ } ++ return ret; ++} ++static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, ++ void *vaddr, dma_addr_t dma_handle) ++{ ++ free_pages((unsigned long)vaddr, get_order(size)); ++} ++#define pci_map_single(cookie, address, size, dir) virt_to_bus(address) ++#define pci_unmap_single(cookie, address, size, dir) ++ ++#endif /* DMA mapping */ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43)) ++ ++#define dev_kfree_skb_any(a) dev_kfree_skb(a) ++#define netif_down(dev) do { (dev)->start = 0; } while (0) ++ ++/* pcmcia-cs provides its own netdevice compatibility layer */ ++#ifndef _COMPAT_NETDEVICE_H ++ ++/* ++ * SoftNet ++ * ++ * For pre-softnet kernels we need to tell the upper layer not to ++ * re-enter start_xmit() while we are in there. However softnet ++ * guarantees not to enter while we are in there so there is no need ++ * to do the netif_stop_queue() dance unless the transmit queue really ++ * gets stuck. This should also improve performance according to tests ++ * done by Aman Singla. ++ */ ++ ++#define dev_kfree_skb_irq(a) dev_kfree_skb(a) ++#define netif_wake_queue(dev) \ ++ do { clear_bit(0, &(dev)->tbusy); mark_bh(NET_BH); } while (0) ++#define netif_stop_queue(dev) set_bit(0, &(dev)->tbusy) ++ ++static inline void netif_start_queue(struct net_device *dev) ++{ ++ dev->tbusy = 0; ++ dev->interrupt = 0; ++ dev->start = 1; ++} ++ ++#define netif_queue_stopped(dev) (dev)->tbusy ++#define netif_running(dev) (dev)->start ++ ++#endif /* _COMPAT_NETDEVICE_H */ ++ ++#define netif_device_attach(dev) netif_start_queue(dev) ++#define netif_device_detach(dev) netif_stop_queue(dev) ++ ++/* 2.4.x renamed bottom halves to tasklets */ ++#define tasklet_struct tq_struct ++static inline void tasklet_schedule(struct tasklet_struct *tasklet) ++{ ++ queue_task(tasklet, &tq_immediate); ++ mark_bh(IMMEDIATE_BH); ++} ++ ++static inline void tasklet_init(struct tasklet_struct *tasklet, ++ void (*func)(unsigned long), ++ unsigned long data) ++{ ++ tasklet->next = NULL; ++ tasklet->sync = 0; ++ tasklet->routine = (void (*)(void *))func; ++ tasklet->data = (void *)data; ++} ++#define tasklet_kill(tasklet) { do {} while (0); } ++ ++/* 2.4.x introduced del_timer_sync() */ ++#define del_timer_sync(timer) del_timer(timer) ++ ++#else ++ ++#define netif_down(dev) ++ ++#endif /* SoftNet */ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3)) ++ ++/* ++ * Emit code to initialise a tq_struct's routine and data pointers ++ */ ++#define PREPARE_TQUEUE(_tq, _routine, _data) \ ++ do { \ ++ (_tq)->routine = _routine; \ ++ (_tq)->data = _data; \ ++ } while (0) ++ ++/* ++ * Emit code to initialise all of a tq_struct ++ */ ++#define INIT_TQUEUE(_tq, _routine, _data) \ ++ do { \ ++ INIT_LIST_HEAD(&(_tq)->list); \ ++ (_tq)->sync = 0; \ ++ PREPARE_TQUEUE((_tq), (_routine), (_data)); \ ++ } while (0) ++ ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3) */ ++ ++/* Power management related macro & routines */ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) ++#define PCI_SAVE_STATE(a, b) pci_save_state(a) ++#define PCI_RESTORE_STATE(a, b) pci_restore_state(a) ++#else ++#define PCI_SAVE_STATE(a, b) pci_save_state(a, b) ++#define PCI_RESTORE_STATE(a, b) pci_restore_state(a, b) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6)) ++static inline int ++pci_save_state(struct pci_dev *dev, u32 *buffer) ++{ ++ int i; ++ if (buffer) { ++ for (i = 0; i < 16; i++) ++ pci_read_config_dword(dev, i * 4, &buffer[i]); ++ } ++ return 0; ++} ++ ++static inline int ++pci_restore_state(struct pci_dev *dev, u32 *buffer) ++{ ++ int i; ++ ++ if (buffer) { ++ for (i = 0; i < 16; i++) ++ pci_write_config_dword(dev, i * 4, buffer[i]); ++ } ++ /* ++ * otherwise, write the context information we know from bootup. ++ * This works around a problem where warm-booting from Windows ++ * combined with a D3(hot)->D0 transition causes PCI config ++ * header data to be forgotten. ++ */ ++ else { ++ for (i = 0; i < 6; i ++) ++ pci_write_config_dword(dev, ++ PCI_BASE_ADDRESS_0 + (i * 4), ++ pci_resource_start(dev, i)); ++ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); ++ } ++ return 0; ++} ++#endif /* PCI power management */ ++ ++/* Old cp0 access macros deprecated in 2.4.19 */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 19)) ++#define read_c0_count() read_32bit_cp0_register(CP0_COUNT) ++#endif ++ ++/* Module refcount handled internally in 2.6.x */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) ++#ifndef SET_MODULE_OWNER ++#define SET_MODULE_OWNER(dev) do {} while (0) ++#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT ++#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT ++#else ++#define OLD_MOD_INC_USE_COUNT do {} while (0) ++#define OLD_MOD_DEC_USE_COUNT do {} while (0) ++#endif ++#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) */ ++#ifndef SET_MODULE_OWNER ++#define SET_MODULE_OWNER(dev) do {} while (0) ++#endif ++#ifndef MOD_INC_USE_COUNT ++#define MOD_INC_USE_COUNT do {} while (0) ++#endif ++#ifndef MOD_DEC_USE_COUNT ++#define MOD_DEC_USE_COUNT do {} while (0) ++#endif ++#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT ++#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) */ ++ ++#ifndef SET_NETDEV_DEV ++#define SET_NETDEV_DEV(net, pdev) do {} while (0) ++#endif ++ ++#ifndef HAVE_FREE_NETDEV ++#define free_netdev(dev) kfree(dev) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++/* struct packet_type redefined in 2.6.x */ ++#define af_packet_priv data ++#endif ++ ++/* suspend args */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) ++#define DRV_SUSPEND_STATE_TYPE pm_message_t ++#else ++#define DRV_SUSPEND_STATE_TYPE uint32 ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) ++#define CHECKSUM_HW CHECKSUM_PARTIAL ++#endif ++ ++typedef struct { ++ void *parent; /* some external entity that the thread supposed to work for */ ++ struct task_struct *p_task; ++ long thr_pid; ++ int prio; /* priority */ ++ struct semaphore sema; ++ int terminated; ++ struct completion completed; ++} tsk_ctl_t; ++ ++ ++/* requires tsk_ctl_t tsk argument, the caller's priv data is passed in owner ptr */ ++/* note this macro assumes there may be only one context waiting on thread's completion */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++#define SMP_RD_BARRIER_DEPENDS(x) smp_read_barrier_depends(x) ++#else ++#define SMP_RD_BARRIER_DEPENDS(x) smp_rmb(x) ++#endif ++ ++ ++#define PROC_START(thread_func, owner, tsk_ctl, flags) \ ++{ \ ++ sema_init(&((tsk_ctl)->sema), 0); \ ++ init_completion(&((tsk_ctl)->completed)); \ ++ (tsk_ctl)->parent = owner; \ ++ (tsk_ctl)->terminated = FALSE; \ ++ (tsk_ctl)->thr_pid = kernel_thread(thread_func, tsk_ctl, flags); \ ++ if ((tsk_ctl)->thr_pid > 0) \ ++ wait_for_completion(&((tsk_ctl)->completed)); \ ++} ++ ++#ifdef USE_KTHREAD_API ++#define PROC_START2(thread_func, owner, tsk_ctl, flags, name) \ ++{ \ ++ sema_init(&((tsk_ctl)->sema), 0); \ ++ init_completion(&((tsk_ctl)->completed)); \ ++ (tsk_ctl)->parent = owner; \ ++ (tsk_ctl)->terminated = FALSE; \ ++ (tsk_ctl)->p_task = kthread_run(thread_func, tsk_ctl, (char*)name); \ ++ (tsk_ctl)->thr_pid = (tsk_ctl)->p_task->pid; \ ++} ++#endif ++ ++#define PROC_STOP(tsk_ctl) \ ++{ \ ++ (tsk_ctl)->terminated = TRUE; \ ++ smp_wmb(); \ ++ up(&((tsk_ctl)->sema)); \ ++ wait_for_completion(&((tsk_ctl)->completed)); \ ++ (tsk_ctl)->thr_pid = -1; \ ++} ++ ++/* ----------------------- */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) ++#define KILL_PROC(nr, sig) \ ++{ \ ++struct task_struct *tsk; \ ++struct pid *pid; \ ++pid = find_get_pid((pid_t)nr); \ ++tsk = pid_task(pid, PIDTYPE_PID); \ ++if (tsk) send_sig(sig, tsk, 1); \ ++} ++#else ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ ++ KERNEL_VERSION(2, 6, 30)) ++#define KILL_PROC(pid, sig) \ ++{ \ ++ struct task_struct *tsk; \ ++ tsk = find_task_by_vpid(pid); \ ++ if (tsk) send_sig(sig, tsk, 1); \ ++} ++#else ++#define KILL_PROC(pid, sig) \ ++{ \ ++ kill_proc(pid, sig, 1); \ ++} ++#endif ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++#include ++#include ++#else ++#include ++ ++#define __wait_event_interruptible_timeout(wq, condition, ret) \ ++do { \ ++ wait_queue_t __wait; \ ++ init_waitqueue_entry(&__wait, current); \ ++ \ ++ add_wait_queue(&wq, &__wait); \ ++ for (;;) { \ ++ set_current_state(TASK_INTERRUPTIBLE); \ ++ if (condition) \ ++ break; \ ++ if (!signal_pending(current)) { \ ++ ret = schedule_timeout(ret); \ ++ if (!ret) \ ++ break; \ ++ continue; \ ++ } \ ++ ret = -ERESTARTSYS; \ ++ break; \ ++ } \ ++ current->state = TASK_RUNNING; \ ++ remove_wait_queue(&wq, &__wait); \ ++} while (0) ++ ++#define wait_event_interruptible_timeout(wq, condition, timeout) \ ++({ \ ++ long __ret = timeout; \ ++ if (!(condition)) \ ++ __wait_event_interruptible_timeout(wq, condition, __ret); \ ++ __ret; \ ++}) ++ ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ ++ ++/* ++For < 2.6.24, wl creates its own netdev but doesn't ++align the priv area like the genuine alloc_netdev(). ++Since netdev_priv() always gives us the aligned address, it will ++not match our unaligned address for < 2.6.24 ++*/ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) ++#define DEV_PRIV(dev) (dev->priv) ++#else ++#define DEV_PRIV(dev) netdev_priv(dev) ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) ++#define WL_ISR(i, d, p) wl_isr((i), (d)) ++#else ++#define WL_ISR(i, d, p) wl_isr((i), (d), (p)) ++#endif /* < 2.6.20 */ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++#define netdev_priv(dev) dev->priv ++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ ++ ++#endif /* _linuxver_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/miniopt.h b/drivers/net/wireless/ap6211/include/miniopt.h +new file mode 100755 +index 0000000..c1eca68 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/miniopt.h +@@ -0,0 +1,77 @@ ++/* ++ * Command line options parser. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * $Id: miniopt.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++ ++#ifndef MINI_OPT_H ++#define MINI_OPT_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* ---- Include Files ---------------------------------------------------- */ ++/* ---- Constants and Types ---------------------------------------------- */ ++ ++#define MINIOPT_MAXKEY 128 /* Max options */ ++typedef struct miniopt { ++ ++ /* These are persistent after miniopt_init() */ ++ const char* name; /* name for prompt in error strings */ ++ const char* flags; /* option chars that take no args */ ++ bool longflags; /* long options may be flags */ ++ bool opt_end; /* at end of options (passed a "--") */ ++ ++ /* These are per-call to miniopt() */ ++ ++ int consumed; /* number of argv entries cosumed in ++ * the most recent call to miniopt() ++ */ ++ bool positional; ++ bool good_int; /* 'val' member is the result of a sucessful ++ * strtol conversion of the option value ++ */ ++ char opt; ++ char key[MINIOPT_MAXKEY]; ++ char* valstr; /* positional param, or value for the option, ++ * or null if the option had ++ * no accompanying value ++ */ ++ uint uval; /* strtol translation of valstr */ ++ int val; /* strtol translation of valstr */ ++} miniopt_t; ++ ++void miniopt_init(miniopt_t *t, const char* name, const char* flags, bool longflags); ++int miniopt(miniopt_t *t, char **argv); ++ ++ ++/* ---- Variable Externs ------------------------------------------------- */ ++/* ---- Function Prototypes ---------------------------------------------- */ ++ ++ ++#ifdef __cplusplus ++ } ++#endif ++ ++#endif /* MINI_OPT_H */ +diff --git a/drivers/net/wireless/ap6211/include/msgtrace.h b/drivers/net/wireless/ap6211/include/msgtrace.h +new file mode 100755 +index 0000000..7c5fd81 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/msgtrace.h +@@ -0,0 +1,74 @@ ++/* ++ * Trace messages sent over HBUS ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: msgtrace.h 281527 2011-09-02 17:12:53Z $ ++ */ ++ ++#ifndef _MSGTRACE_H ++#define _MSGTRACE_H ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++#define MSGTRACE_VERSION 1 ++ ++/* Message trace header */ ++typedef BWL_PRE_PACKED_STRUCT struct msgtrace_hdr { ++ uint8 version; ++ uint8 spare; ++ uint16 len; /* Len of the trace */ ++ uint32 seqnum; /* Sequence number of message. Useful if the messsage has been lost ++ * because of DMA error or a bus reset (ex: SDIO Func2) ++ */ ++ uint32 discarded_bytes; /* Number of discarded bytes because of trace overflow */ ++ uint32 discarded_printf; /* Number of discarded printf because of trace overflow */ ++} BWL_POST_PACKED_STRUCT msgtrace_hdr_t; ++ ++#define MSGTRACE_HDRLEN sizeof(msgtrace_hdr_t) ++ ++/* The hbus driver generates traces when sending a trace message. This causes endless traces. ++ * This flag must be set to TRUE in any hbus traces. The flag is reset in the function msgtrace_put. ++ * This prevents endless traces but generates hasardous lost of traces only in bus device code. ++ * It is recommendat to set this flag in macro SD_TRACE but not in SD_ERROR for avoiding missing ++ * hbus error traces. hbus error trace should not generates endless traces. ++ */ ++extern bool msgtrace_hbus_trace; ++ ++typedef void (*msgtrace_func_send_t)(void *hdl1, void *hdl2, uint8 *hdr, ++ uint16 hdrlen, uint8 *buf, uint16 buflen); ++extern void msgtrace_start(void); ++extern void msgtrace_stop(void); ++extern void msgtrace_sent(void); ++extern void msgtrace_put(char *buf, int count); ++extern void msgtrace_init(void *hdl1, void *hdl2, msgtrace_func_send_t func_send); ++extern bool msgtrace_event_enabled(void); ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _MSGTRACE_H */ +diff --git a/drivers/net/wireless/ap6211/include/osl.h b/drivers/net/wireless/ap6211/include/osl.h +new file mode 100755 +index 0000000..0a11d23 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/osl.h +@@ -0,0 +1,90 @@ ++/* ++ * OS Abstraction Layer ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: osl.h 320905 2012-03-13 15:33:25Z $ ++ */ ++ ++#ifndef _osl_h_ ++#define _osl_h_ ++ ++/* osl handle type forward declaration */ ++typedef struct osl_info osl_t; ++typedef struct osl_dmainfo osldma_t; ++ ++#define OSL_PKTTAG_SZ 32 /* Size of PktTag */ ++ ++/* Drivers use PKTFREESETCB to register a callback function when a packet is freed by OSL */ ++typedef void (*pktfree_cb_fn_t)(void *ctx, void *pkt, unsigned int status); ++ ++/* Drivers use REGOPSSET() to register register read/write funcitons */ ++typedef unsigned int (*osl_rreg_fn_t)(void *ctx, volatile void *reg, unsigned int size); ++typedef void (*osl_wreg_fn_t)(void *ctx, volatile void *reg, unsigned int val, unsigned int size); ++ ++ ++#include ++ ++#ifndef PKTDBG_TRACE ++#define PKTDBG_TRACE(osh, pkt, bit) ++#endif ++ ++#define PKTCTFMAP(osh, p) ++ ++/* -------------------------------------------------------------------------- ++** Register manipulation macros. ++*/ ++ ++#define SET_REG(osh, r, mask, val) W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val))) ++ ++#ifndef AND_REG ++#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) ++#endif /* !AND_REG */ ++ ++#ifndef OR_REG ++#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) ++#endif /* !OR_REG */ ++ ++#if !defined(OSL_SYSUPTIME) ++#define OSL_SYSUPTIME() (0) ++#define OSL_SYSUPTIME_SUPPORT FALSE ++#else ++#define OSL_SYSUPTIME_SUPPORT TRUE ++#endif /* OSL_SYSUPTIME */ ++ ++#if !defined(PKTC) ++#define PKTCCNT(skb) (0) ++#define PKTCLEN(skb) (0) ++#define PKTCFLAGS(skb) (0) ++#define PKTCSETCNT(skb, c) ++#define PKTCSETLEN(skb, l) ++#define PKTCSETFLAG(skb, fb) ++#define PKTCCLRFLAG(skb, fb) ++#define PKTCLINK(skb) PKTLINK(skb) ++#define PKTSETCLINK(skb, x) PKTSETLINK((skb), (x)) ++#define PKTISCHAINED(skb) FALSE ++#define FOREACH_CHAINED_PKT(skb, nskb) \ ++ for ((nskb) = NULL; (skb) != NULL; (skb) = (nskb)) ++#define PKTCFREE PKTFREE ++#endif ++ ++ ++#endif /* _osl_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/packed_section_end.h b/drivers/net/wireless/ap6211/include/packed_section_end.h +new file mode 100755 +index 0000000..0779b04 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/packed_section_end.h +@@ -0,0 +1,59 @@ ++/* ++ * Declare directives for structure packing. No padding will be provided ++ * between the members of packed structures, and therefore, there is no ++ * guarantee that structure members will be aligned. ++ * ++ * Declaring packed structures is compiler specific. In order to handle all ++ * cases, packed structures should be delared as: ++ * ++ * #include ++ * ++ * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { ++ * some_struct_members; ++ * } BWL_POST_PACKED_STRUCT foobar_t; ++ * ++ * #include ++ * ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * $Id: packed_section_end.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++ ++/* Error check - BWL_PACKED_SECTION is defined in packed_section_start.h ++ * and undefined in packed_section_end.h. If it is NOT defined at this ++ * point, then there is a missing include of packed_section_start.h. ++ */ ++#ifdef BWL_PACKED_SECTION ++ #undef BWL_PACKED_SECTION ++#else ++ #error "BWL_PACKED_SECTION is NOT defined!" ++#endif ++ ++ ++ ++ ++/* Compiler-specific directives for structure packing are declared in ++ * packed_section_start.h. This marks the end of the structure packing section, ++ * so, undef them here. ++ */ ++#undef BWL_PRE_PACKED_STRUCT ++#undef BWL_POST_PACKED_STRUCT +diff --git a/drivers/net/wireless/ap6211/include/packed_section_start.h b/drivers/net/wireless/ap6211/include/packed_section_start.h +new file mode 100755 +index 0000000..ee93a4b +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/packed_section_start.h +@@ -0,0 +1,63 @@ ++/* ++ * Declare directives for structure packing. No padding will be provided ++ * between the members of packed structures, and therefore, there is no ++ * guarantee that structure members will be aligned. ++ * ++ * Declaring packed structures is compiler specific. In order to handle all ++ * cases, packed structures should be delared as: ++ * ++ * #include ++ * ++ * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { ++ * some_struct_members; ++ * } BWL_POST_PACKED_STRUCT foobar_t; ++ * ++ * #include ++ * ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * $Id: packed_section_start.h 286783 2011-09-29 06:18:57Z $ ++ */ ++ ++ ++/* Error check - BWL_PACKED_SECTION is defined in packed_section_start.h ++ * and undefined in packed_section_end.h. If it is already defined at this ++ * point, then there is a missing include of packed_section_end.h. ++ */ ++#ifdef BWL_PACKED_SECTION ++ #error "BWL_PACKED_SECTION is already defined!" ++#else ++ #define BWL_PACKED_SECTION ++#endif ++ ++ ++ ++ ++/* Declare compiler-specific directives for structure packing. */ ++#if defined(__GNUC__) || defined(__lint) ++ #define BWL_PRE_PACKED_STRUCT ++ #define BWL_POST_PACKED_STRUCT __attribute__ ((packed)) ++#elif defined(__CC_ARM) ++ #define BWL_PRE_PACKED_STRUCT __packed ++ #define BWL_POST_PACKED_STRUCT ++#else ++ #error "Unknown compiler!" ++#endif +diff --git a/drivers/net/wireless/ap6211/include/pcicfg.h b/drivers/net/wireless/ap6211/include/pcicfg.h +new file mode 100755 +index 0000000..0278bb2 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/pcicfg.h +@@ -0,0 +1,100 @@ ++/* ++ * pcicfg.h: PCI configuration constants and structures. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: pcicfg.h 309193 2012-01-19 00:03:57Z $ ++ */ ++ ++#ifndef _h_pcicfg_ ++#define _h_pcicfg_ ++ ++/* A structure for the config registers is nice, but in most ++ * systems the config space is not memory mapped, so we need ++ * field offsetts. :-( ++ */ ++#define PCI_CFG_VID 0 ++#define PCI_CFG_DID 2 ++#define PCI_CFG_CMD 4 ++#define PCI_CFG_STAT 6 ++#define PCI_CFG_REV 8 ++#define PCI_CFG_PROGIF 9 ++#define PCI_CFG_SUBCL 0xa ++#define PCI_CFG_BASECL 0xb ++#define PCI_CFG_CLSZ 0xc ++#define PCI_CFG_LATTIM 0xd ++#define PCI_CFG_HDR 0xe ++#define PCI_CFG_BIST 0xf ++#define PCI_CFG_BAR0 0x10 ++#define PCI_CFG_BAR1 0x14 ++#define PCI_CFG_BAR2 0x18 ++#define PCI_CFG_BAR3 0x1c ++#define PCI_CFG_BAR4 0x20 ++#define PCI_CFG_BAR5 0x24 ++#define PCI_CFG_CIS 0x28 ++#define PCI_CFG_SVID 0x2c ++#define PCI_CFG_SSID 0x2e ++#define PCI_CFG_ROMBAR 0x30 ++#define PCI_CFG_CAPPTR 0x34 ++#define PCI_CFG_INT 0x3c ++#define PCI_CFG_PIN 0x3d ++#define PCI_CFG_MINGNT 0x3e ++#define PCI_CFG_MAXLAT 0x3f ++#define PCI_BAR0_WIN 0x80 /* backplane addres space accessed by BAR0 */ ++#define PCI_BAR1_WIN 0x84 /* backplane addres space accessed by BAR1 */ ++#define PCI_SPROM_CONTROL 0x88 /* sprom property control */ ++#define PCI_BAR1_CONTROL 0x8c /* BAR1 region burst control */ ++#define PCI_INT_STATUS 0x90 /* PCI and other cores interrupts */ ++#define PCI_INT_MASK 0x94 /* mask of PCI and other cores interrupts */ ++#define PCI_TO_SB_MB 0x98 /* signal backplane interrupts */ ++#define PCI_BACKPLANE_ADDR 0xa0 /* address an arbitrary location on the system backplane */ ++#define PCI_BACKPLANE_DATA 0xa4 /* data at the location specified by above address */ ++#define PCI_CLK_CTL_ST 0xa8 /* pci config space clock control/status (>=rev14) */ ++#define PCI_BAR0_WIN2 0xac /* backplane addres space accessed by second 4KB of BAR0 */ ++#define PCI_GPIO_IN 0xb0 /* pci config space gpio input (>=rev3) */ ++#define PCI_GPIO_OUT 0xb4 /* pci config space gpio output (>=rev3) */ ++#define PCI_GPIO_OUTEN 0xb8 /* pci config space gpio output enable (>=rev3) */ ++ ++#define PCI_BAR0_SHADOW_OFFSET (2 * 1024) /* bar0 + 2K accesses sprom shadow (in pci core) */ ++#define PCI_BAR0_SPROM_OFFSET (4 * 1024) /* bar0 + 4K accesses external sprom */ ++#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024) /* bar0 + 6K accesses pci core registers */ ++#define PCI_BAR0_PCISBR_OFFSET (4 * 1024) /* pci core SB registers are at the end of the ++ * 8KB window, so their address is the "regular" ++ * address plus 4K ++ */ ++/* ++ * PCIE GEN2 changed some of the above locations for ++ * Bar0WrapperBase, SecondaryBAR0Window and SecondaryBAR0WrapperBase ++ * BAR0 maps 32K of register space ++*/ ++#define PCIE2_BAR0_WIN2 0x70 /* backplane addres space accessed by second 4KB of BAR0 */ ++#define PCIE2_BAR0_CORE2_WIN 0x74 /* backplane addres space accessed by second 4KB of BAR0 */ ++#define PCIE2_BAR0_CORE2_WIN2 0x78 /* backplane addres space accessed by second 4KB of BAR0 */ ++ ++#define PCI_BAR0_WINSZ (16 * 1024) /* bar0 window size Match with corerev 13 */ ++/* On pci corerev >= 13 and all pcie, the bar0 is now 16KB and it maps: */ ++#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024) /* bar0 + 8K accesses pci/pcie core registers */ ++#define PCI_16KB0_CCREGS_OFFSET (12 * 1024) /* bar0 + 12K accesses chipc core registers */ ++#define PCI_16KBB0_WINSZ (16 * 1024) /* bar0 window size */ ++ ++ ++#define PCI_CONFIG_SPACE_SIZE 256 ++#endif /* _h_pcicfg_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/802.11.h b/drivers/net/wireless/ap6211/include/proto/802.11.h +new file mode 100755 +index 0000000..15cd56c +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/802.11.h +@@ -0,0 +1,2355 @@ ++/* ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * Fundamental types and constants relating to 802.11 ++ * ++ * $Id: 802.11.h 346820 2012-07-24 13:53:12Z $ ++ */ ++ ++#ifndef _802_11_H_ ++#define _802_11_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++#ifndef _NET_ETHERNET_H_ ++#include ++#endif ++ ++#include ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++#define DOT11_TU_TO_US 1024 /* 802.11 Time Unit is 1024 microseconds */ ++ ++/* Generic 802.11 frame constants */ ++#define DOT11_A3_HDR_LEN 24 /* d11 header length with A3 */ ++#define DOT11_A4_HDR_LEN 30 /* d11 header length with A4 */ ++#define DOT11_MAC_HDR_LEN DOT11_A3_HDR_LEN /* MAC header length */ ++#define DOT11_FCS_LEN 4 /* d11 FCS length */ ++#define DOT11_ICV_LEN 4 /* d11 ICV length */ ++#define DOT11_ICV_AES_LEN 8 /* d11 ICV/AES length */ ++#define DOT11_QOS_LEN 2 /* d11 QoS length */ ++#define DOT11_HTC_LEN 4 /* d11 HT Control field length */ ++ ++#define DOT11_KEY_INDEX_SHIFT 6 /* d11 key index shift */ ++#define DOT11_IV_LEN 4 /* d11 IV length */ ++#define DOT11_IV_TKIP_LEN 8 /* d11 IV TKIP length */ ++#define DOT11_IV_AES_OCB_LEN 4 /* d11 IV/AES/OCB length */ ++#define DOT11_IV_AES_CCM_LEN 8 /* d11 IV/AES/CCM length */ ++#define DOT11_IV_MAX_LEN 8 /* maximum iv len for any encryption */ ++ ++/* Includes MIC */ ++#define DOT11_MAX_MPDU_BODY_LEN 2304 /* max MPDU body length */ ++/* A4 header + QoS + CCMP + PDU + ICV + FCS = 2352 */ ++#define DOT11_MAX_MPDU_LEN (DOT11_A4_HDR_LEN + \ ++ DOT11_QOS_LEN + \ ++ DOT11_IV_AES_CCM_LEN + \ ++ DOT11_MAX_MPDU_BODY_LEN + \ ++ DOT11_ICV_LEN + \ ++ DOT11_FCS_LEN) /* d11 max MPDU length */ ++ ++#define DOT11_MAX_SSID_LEN 32 /* d11 max ssid length */ ++ ++/* dot11RTSThreshold */ ++#define DOT11_DEFAULT_RTS_LEN 2347 /* d11 default RTS length */ ++#define DOT11_MAX_RTS_LEN 2347 /* d11 max RTS length */ ++ ++/* dot11FragmentationThreshold */ ++#define DOT11_MIN_FRAG_LEN 256 /* d11 min fragmentation length */ ++#define DOT11_MAX_FRAG_LEN 2346 /* Max frag is also limited by aMPDUMaxLength ++ * of the attached PHY ++ */ ++#define DOT11_DEFAULT_FRAG_LEN 2346 /* d11 default fragmentation length */ ++ ++/* dot11BeaconPeriod */ ++#define DOT11_MIN_BEACON_PERIOD 1 /* d11 min beacon period */ ++#define DOT11_MAX_BEACON_PERIOD 0xFFFF /* d11 max beacon period */ ++ ++/* dot11DTIMPeriod */ ++#define DOT11_MIN_DTIM_PERIOD 1 /* d11 min DTIM period */ ++#define DOT11_MAX_DTIM_PERIOD 0xFF /* d11 max DTIM period */ ++ ++/* 802.2 LLC/SNAP header used by 802.11 per 802.1H */ ++#define DOT11_LLC_SNAP_HDR_LEN 8 /* d11 LLC/SNAP header length */ ++#define DOT11_OUI_LEN 3 /* d11 OUI length */ ++BWL_PRE_PACKED_STRUCT struct dot11_llc_snap_header { ++ uint8 dsap; /* always 0xAA */ ++ uint8 ssap; /* always 0xAA */ ++ uint8 ctl; /* always 0x03 */ ++ uint8 oui[DOT11_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00 ++ * Bridge-Tunnel: 0x00 0x00 0xF8 ++ */ ++ uint16 type; /* ethertype */ ++} BWL_POST_PACKED_STRUCT; ++ ++/* RFC1042 header used by 802.11 per 802.1H */ ++#define RFC1042_HDR_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN) /* RCF1042 header length */ ++ ++/* Generic 802.11 MAC header */ ++/* ++ * N.B.: This struct reflects the full 4 address 802.11 MAC header. ++ * The fields are defined such that the shorter 1, 2, and 3 ++ * address headers just use the first k fields. ++ */ ++BWL_PRE_PACKED_STRUCT struct dot11_header { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr a1; /* address 1 */ ++ struct ether_addr a2; /* address 2 */ ++ struct ether_addr a3; /* address 3 */ ++ uint16 seq; /* sequence control */ ++ struct ether_addr a4; /* address 4 */ ++} BWL_POST_PACKED_STRUCT; ++ ++/* Control frames */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rts_frame { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr ra; /* receiver address */ ++ struct ether_addr ta; /* transmitter address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_RTS_LEN 16 /* d11 RTS frame length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_cts_frame { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr ra; /* receiver address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_CTS_LEN 10 /* d11 CTS frame length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ack_frame { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr ra; /* receiver address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_ACK_LEN 10 /* d11 ACK frame length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ps_poll_frame { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* AID */ ++ struct ether_addr bssid; /* receiver address, STA in AP */ ++ struct ether_addr ta; /* transmitter address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_PS_POLL_LEN 16 /* d11 PS poll frame length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_cf_end_frame { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr ra; /* receiver address */ ++ struct ether_addr bssid; /* transmitter address, STA in AP */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_CS_END_LEN 16 /* d11 CF-END frame length */ ++ ++/* RWL wifi protocol: The Vendor Specific Action frame is defined for vendor-specific signaling ++* category+OUI+vendor specific content ( this can be variable) ++*/ ++BWL_PRE_PACKED_STRUCT struct dot11_action_wifi_vendor_specific { ++ uint8 category; ++ uint8 OUI[3]; ++ uint8 type; ++ uint8 subtype; ++ uint8 data[1040]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_action_wifi_vendor_specific dot11_action_wifi_vendor_specific_t; ++ ++/* generic vender specific action frame with variable length */ ++BWL_PRE_PACKED_STRUCT struct dot11_action_vs_frmhdr { ++ uint8 category; ++ uint8 OUI[3]; ++ uint8 type; ++ uint8 subtype; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_action_vs_frmhdr dot11_action_vs_frmhdr_t; ++#define DOT11_ACTION_VS_HDR_LEN 6 ++ ++#define BCM_ACTION_OUI_BYTE0 0x00 ++#define BCM_ACTION_OUI_BYTE1 0x90 ++#define BCM_ACTION_OUI_BYTE2 0x4c ++ ++/* BA/BAR Control parameters */ ++#define DOT11_BA_CTL_POLICY_NORMAL 0x0000 /* normal ack */ ++#define DOT11_BA_CTL_POLICY_NOACK 0x0001 /* no ack */ ++#define DOT11_BA_CTL_POLICY_MASK 0x0001 /* ack policy mask */ ++ ++#define DOT11_BA_CTL_MTID 0x0002 /* multi tid BA */ ++#define DOT11_BA_CTL_COMPRESSED 0x0004 /* compressed bitmap */ ++ ++#define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0 /* num msdu in bitmap mask */ ++#define DOT11_BA_CTL_NUMMSDU_SHIFT 6 /* num msdu in bitmap shift */ ++ ++#define DOT11_BA_CTL_TID_MASK 0xF000 /* tid mask */ ++#define DOT11_BA_CTL_TID_SHIFT 12 /* tid shift */ ++ ++/* control frame header (BA/BAR) */ ++BWL_PRE_PACKED_STRUCT struct dot11_ctl_header { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr ra; /* receiver address */ ++ struct ether_addr ta; /* transmitter address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_CTL_HDR_LEN 16 /* control frame hdr len */ ++ ++/* BAR frame payload */ ++BWL_PRE_PACKED_STRUCT struct dot11_bar { ++ uint16 bar_control; /* BAR Control */ ++ uint16 seqnum; /* Starting Sequence control */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_BAR_LEN 4 /* BAR frame payload length */ ++ ++#define DOT11_BA_BITMAP_LEN 128 /* bitmap length */ ++#define DOT11_BA_CMP_BITMAP_LEN 8 /* compressed bitmap length */ ++/* BA frame payload */ ++BWL_PRE_PACKED_STRUCT struct dot11_ba { ++ uint16 ba_control; /* BA Control */ ++ uint16 seqnum; /* Starting Sequence control */ ++ uint8 bitmap[DOT11_BA_BITMAP_LEN]; /* Block Ack Bitmap */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_BA_LEN 4 /* BA frame payload len (wo bitmap) */ ++ ++/* Management frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_management_header { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr da; /* receiver address */ ++ struct ether_addr sa; /* transmitter address */ ++ struct ether_addr bssid; /* BSS ID */ ++ uint16 seq; /* sequence control */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_MGMT_HDR_LEN 24 /* d11 management header length */ ++ ++/* Management frame payloads */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_bcn_prb { ++ uint32 timestamp[2]; ++ uint16 beacon_interval; ++ uint16 capability; ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_BCN_PRB_LEN 12 /* 802.11 beacon/probe frame fixed length */ ++#define DOT11_BCN_PRB_FIXED_LEN 12 /* 802.11 beacon/probe frame fixed length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_auth { ++ uint16 alg; /* algorithm */ ++ uint16 seq; /* sequence control */ ++ uint16 status; /* status code */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_AUTH_FIXED_LEN 6 /* length of auth frame without challenge IE */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_assoc_req { ++ uint16 capability; /* capability information */ ++ uint16 listen; /* listen interval */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_ASSOC_REQ_FIXED_LEN 4 /* length of assoc frame without info elts */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_reassoc_req { ++ uint16 capability; /* capability information */ ++ uint16 listen; /* listen interval */ ++ struct ether_addr ap; /* Current AP address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_REASSOC_REQ_FIXED_LEN 10 /* length of assoc frame without info elts */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_assoc_resp { ++ uint16 capability; /* capability information */ ++ uint16 status; /* status code */ ++ uint16 aid; /* association ID */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_ASSOC_RESP_FIXED_LEN 6 /* length of assoc resp frame without info elts */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_measure { ++ uint8 category; ++ uint8 action; ++ uint8 token; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_ACTION_MEASURE_LEN 3 /* d11 action measurement header length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_ht_ch_width { ++ uint8 category; ++ uint8 action; ++ uint8 ch_width; ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_ht_mimops { ++ uint8 category; ++ uint8 action; ++ uint8 control; ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_sa_query { ++ uint8 category; ++ uint8 action; ++ uint16 id; ++} BWL_POST_PACKED_STRUCT; ++ ++#define SM_PWRSAVE_ENABLE 1 ++#define SM_PWRSAVE_MODE 2 ++ ++/* ************* 802.11h related definitions. ************* */ ++BWL_PRE_PACKED_STRUCT struct dot11_power_cnst { ++ uint8 id; ++ uint8 len; ++ uint8 power; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_power_cnst dot11_power_cnst_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_power_cap { ++ uint8 min; ++ uint8 max; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_power_cap dot11_power_cap_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_tpc_rep { ++ uint8 id; ++ uint8 len; ++ uint8 tx_pwr; ++ uint8 margin; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tpc_rep dot11_tpc_rep_t; ++#define DOT11_MNG_IE_TPC_REPORT_LEN 2 /* length of IE data, not including 2 byte header */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_supp_channels { ++ uint8 id; ++ uint8 len; ++ uint8 first_channel; ++ uint8 num_channels; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_supp_channels dot11_supp_channels_t; ++ ++/* Extension Channel Offset IE: 802.11n-D1.0 spec. added sideband ++ * offset for 40MHz operation. The possible 3 values are: ++ * 1 = above control channel ++ * 3 = below control channel ++ * 0 = no extension channel ++ */ ++BWL_PRE_PACKED_STRUCT struct dot11_extch { ++ uint8 id; /* IE ID, 62, DOT11_MNG_EXT_CHANNEL_OFFSET */ ++ uint8 len; /* IE length */ ++ uint8 extch; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_extch dot11_extch_ie_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_brcm_extch { ++ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ ++ uint8 len; /* IE length */ ++ uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ ++ uint8 type; /* type inidicates what follows */ ++ uint8 extch; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t; ++ ++#define BRCM_EXTCH_IE_LEN 5 ++#define BRCM_EXTCH_IE_TYPE 53 /* 802.11n ID not yet assigned */ ++#define DOT11_EXTCH_IE_LEN 1 ++#define DOT11_EXT_CH_MASK 0x03 /* extension channel mask */ ++#define DOT11_EXT_CH_UPPER 0x01 /* ext. ch. on upper sb */ ++#define DOT11_EXT_CH_LOWER 0x03 /* ext. ch. on lower sb */ ++#define DOT11_EXT_CH_NONE 0x00 /* no extension ch. */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_frmhdr { ++ uint8 category; ++ uint8 action; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_ACTION_FRMHDR_LEN 2 ++ ++/* CSA IE data structure */ ++BWL_PRE_PACKED_STRUCT struct dot11_channel_switch { ++ uint8 id; /* id DOT11_MNG_CHANNEL_SWITCH_ID */ ++ uint8 len; /* length of IE */ ++ uint8 mode; /* mode 0 or 1 */ ++ uint8 channel; /* channel switch to */ ++ uint8 count; /* number of beacons before switching */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_channel_switch dot11_chan_switch_ie_t; ++ ++#define DOT11_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */ ++/* CSA mode - 802.11h-2003 $7.3.2.20 */ ++#define DOT11_CSA_MODE_ADVISORY 0 /* no DOT11_CSA_MODE_NO_TX restriction imposed */ ++#define DOT11_CSA_MODE_NO_TX 1 /* no transmission upon receiving CSA frame. */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_switch_channel { ++ uint8 category; ++ uint8 action; ++ dot11_chan_switch_ie_t chan_switch_ie; /* for switch IE */ ++ dot11_brcm_extch_ie_t extch_ie; /* extension channel offset */ ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_csa_body { ++ uint8 mode; /* mode 0 or 1 */ ++ uint8 reg; /* regulatory class */ ++ uint8 channel; /* channel switch to */ ++ uint8 count; /* number of beacons before switching */ ++} BWL_POST_PACKED_STRUCT; ++ ++/* 11n Extended Channel Switch IE data structure */ ++BWL_PRE_PACKED_STRUCT struct dot11_ext_csa { ++ uint8 id; /* id DOT11_MNG_EXT_CHANNEL_SWITCH_ID */ ++ uint8 len; /* length of IE */ ++ struct dot11_csa_body b; /* body of the ie */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ext_csa dot11_ext_csa_ie_t; ++#define DOT11_EXT_CSA_IE_LEN 4 /* length of extended channel switch IE body */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_ext_csa { ++ uint8 category; ++ uint8 action; ++ dot11_ext_csa_ie_t chan_switch_ie; /* for switch IE */ ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct dot11y_action_ext_csa { ++ uint8 category; ++ uint8 action; ++ struct dot11_csa_body b; /* body of the ie */ ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_obss_coex { ++ uint8 id; ++ uint8 len; ++ uint8 info; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_obss_coex dot11_obss_coex_t; ++#define DOT11_OBSS_COEXINFO_LEN 1 /* length of OBSS Coexistence INFO IE */ ++ ++#define DOT11_OBSS_COEX_INFO_REQ 0x01 ++#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02 ++#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_obss_chanlist { ++ uint8 id; ++ uint8 len; ++ uint8 regclass; ++ uint8 chanlist[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_obss_chanlist dot11_obss_chanlist_t; ++#define DOT11_OBSS_CHANLIST_FIXED_LEN 1 /* fixed length of regclass */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie { ++ uint8 id; ++ uint8 len; ++ uint8 cap[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_extcap_ie dot11_extcap_ie_t; ++ ++#define DOT11_EXTCAP_LEN_MAX 7 ++#define DOT11_EXTCAP_LEN_COEX 1 ++#define DOT11_EXTCAP_LEN_BT 3 ++#define DOT11_EXTCAP_LEN_IW 4 ++#define DOT11_EXTCAP_LEN_SI 6 ++ ++#define DOT11_EXTCAP_LEN_TDLS 5 ++BWL_PRE_PACKED_STRUCT struct dot11_extcap { ++ uint8 extcap[DOT11_EXTCAP_LEN_TDLS]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_extcap dot11_extcap_t; ++ ++/* TDLS Capabilities */ ++#define TDLS_CAP_TDLS 37 /* TDLS support */ ++#define TDLS_CAP_PU_BUFFER_STA 28 /* TDLS Peer U-APSD buffer STA support */ ++#define TDLS_CAP_PEER_PSM 20 /* TDLS Peer PSM support */ ++#define TDLS_CAP_CH_SW 30 /* TDLS Channel switch */ ++#define TDLS_CAP_PROH 38 /* TDLS prohibited */ ++#define TDLS_CAP_CH_SW_PROH 39 /* TDLS Channel switch prohibited */ ++ ++#define TDLS_CAP_MAX_BIT 39 /* TDLS max bit defined in ext cap */ ++ ++/* 802.11h/802.11k Measurement Request/Report IEs */ ++/* Measurement Type field */ ++#define DOT11_MEASURE_TYPE_BASIC 0 /* d11 measurement basic type */ ++#define DOT11_MEASURE_TYPE_CCA 1 /* d11 measurement CCA type */ ++#define DOT11_MEASURE_TYPE_RPI 2 /* d11 measurement RPI type */ ++#define DOT11_MEASURE_TYPE_CHLOAD 3 /* d11 measurement Channel Load type */ ++#define DOT11_MEASURE_TYPE_NOISE 4 /* d11 measurement Noise Histogram type */ ++#define DOT11_MEASURE_TYPE_BEACON 5 /* d11 measurement Beacon type */ ++#define DOT11_MEASURE_TYPE_FRAME 6 /* d11 measurement Frame type */ ++#define DOT11_MEASURE_TYPE_STATS 7 /* d11 measurement STA Statistics type */ ++#define DOT11_MEASURE_TYPE_LCI 8 /* d11 measurement LCI type */ ++#define DOT11_MEASURE_TYPE_TXSTREAM 9 /* d11 measurement TX Stream type */ ++#define DOT11_MEASURE_TYPE_PAUSE 255 /* d11 measurement pause type */ ++ ++/* Measurement Request Modes */ ++#define DOT11_MEASURE_MODE_PARALLEL (1<<0) /* d11 measurement parallel */ ++#define DOT11_MEASURE_MODE_ENABLE (1<<1) /* d11 measurement enable */ ++#define DOT11_MEASURE_MODE_REQUEST (1<<2) /* d11 measurement request */ ++#define DOT11_MEASURE_MODE_REPORT (1<<3) /* d11 measurement report */ ++#define DOT11_MEASURE_MODE_DUR (1<<4) /* d11 measurement dur mandatory */ ++/* Measurement Report Modes */ ++#define DOT11_MEASURE_MODE_LATE (1<<0) /* d11 measurement late */ ++#define DOT11_MEASURE_MODE_INCAPABLE (1<<1) /* d11 measurement incapable */ ++#define DOT11_MEASURE_MODE_REFUSED (1<<2) /* d11 measurement refuse */ ++/* Basic Measurement Map bits */ ++#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0)) /* d11 measurement basic map BSS */ ++#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1)) /* d11 measurement map OFDM */ ++#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2)) /* d11 measurement map unknown */ ++#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3)) /* d11 measurement map radar */ ++#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4)) /* d11 measurement map unmeasuremnt */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_meas_req { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint8 channel; ++ uint8 start_time[8]; ++ uint16 duration; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_meas_req dot11_meas_req_t; ++#define DOT11_MNG_IE_MREQ_LEN 14 /* d11 measurement request IE length */ ++/* length of Measure Request IE data not including variable len */ ++#define DOT11_MNG_IE_MREQ_FIXED_LEN 3 /* d11 measurement request IE fixed length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_meas_rep { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ BWL_PRE_PACKED_STRUCT union ++ { ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 channel; ++ uint8 start_time[8]; ++ uint16 duration; ++ uint8 map; ++ } BWL_POST_PACKED_STRUCT basic; ++ uint8 data[1]; ++ } BWL_POST_PACKED_STRUCT rep; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_meas_rep dot11_meas_rep_t; ++ ++/* length of Measure Report IE data not including variable len */ ++#define DOT11_MNG_IE_MREP_FIXED_LEN 3 /* d11 measurement response IE fixed length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_meas_rep_basic { ++ uint8 channel; ++ uint8 start_time[8]; ++ uint16 duration; ++ uint8 map; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t; ++#define DOT11_MEASURE_BASIC_REP_LEN 12 /* d11 measurement basic report length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_quiet { ++ uint8 id; ++ uint8 len; ++ uint8 count; /* TBTTs until beacon interval in quiet starts */ ++ uint8 period; /* Beacon intervals between periodic quiet periods ? */ ++ uint16 duration; /* Length of quiet period, in TU's */ ++ uint16 offset; /* TU's offset from TBTT in Count field */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_quiet dot11_quiet_t; ++ ++BWL_PRE_PACKED_STRUCT struct chan_map_tuple { ++ uint8 channel; ++ uint8 map; ++} BWL_POST_PACKED_STRUCT; ++typedef struct chan_map_tuple chan_map_tuple_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ibss_dfs { ++ uint8 id; ++ uint8 len; ++ uint8 eaddr[ETHER_ADDR_LEN]; ++ uint8 interval; ++ chan_map_tuple_t map[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ibss_dfs dot11_ibss_dfs_t; ++ ++/* WME Elements */ ++#define WME_OUI "\x00\x50\xf2" /* WME OUI */ ++#define WME_OUI_LEN 3 ++#define WME_OUI_TYPE 2 /* WME type */ ++#define WME_TYPE 2 /* WME type, deprecated */ ++#define WME_SUBTYPE_IE 0 /* Information Element */ ++#define WME_SUBTYPE_PARAM_IE 1 /* Parameter Element */ ++#define WME_SUBTYPE_TSPEC 2 /* Traffic Specification */ ++#define WME_VER 1 /* WME version */ ++ ++/* WME Access Category Indices (ACIs) */ ++#define AC_BE 0 /* Best Effort */ ++#define AC_BK 1 /* Background */ ++#define AC_VI 2 /* Video */ ++#define AC_VO 3 /* Voice */ ++#define AC_COUNT 4 /* number of ACs */ ++ ++typedef uint8 ac_bitmap_t; /* AC bitmap of (1 << AC_xx) */ ++ ++#define AC_BITMAP_NONE 0x0 /* No ACs */ ++#define AC_BITMAP_ALL 0xf /* All ACs */ ++#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0) ++#define AC_BITMAP_SET(ab, ac) (((ab) |= (1 << (ac)))) ++#define AC_BITMAP_RESET(ab, ac) (((ab) &= ~(1 << (ac)))) ++ ++/* WME Information Element (IE) */ ++BWL_PRE_PACKED_STRUCT struct wme_ie { ++ uint8 oui[3]; ++ uint8 type; ++ uint8 subtype; ++ uint8 version; ++ uint8 qosinfo; ++} BWL_POST_PACKED_STRUCT; ++typedef struct wme_ie wme_ie_t; ++#define WME_IE_LEN 7 /* WME IE length */ ++ ++BWL_PRE_PACKED_STRUCT struct edcf_acparam { ++ uint8 ACI; ++ uint8 ECW; ++ uint16 TXOP; /* stored in network order (ls octet first) */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct edcf_acparam edcf_acparam_t; ++ ++/* WME Parameter Element (PE) */ ++BWL_PRE_PACKED_STRUCT struct wme_param_ie { ++ uint8 oui[3]; ++ uint8 type; ++ uint8 subtype; ++ uint8 version; ++ uint8 qosinfo; ++ uint8 rsvd; ++ edcf_acparam_t acparam[AC_COUNT]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct wme_param_ie wme_param_ie_t; ++#define WME_PARAM_IE_LEN 24 /* WME Parameter IE length */ ++ ++/* QoS Info field for IE as sent from AP */ ++#define WME_QI_AP_APSD_MASK 0x80 /* U-APSD Supported mask */ ++#define WME_QI_AP_APSD_SHIFT 7 /* U-APSD Supported shift */ ++#define WME_QI_AP_COUNT_MASK 0x0f /* Parameter set count mask */ ++#define WME_QI_AP_COUNT_SHIFT 0 /* Parameter set count shift */ ++ ++/* QoS Info field for IE as sent from STA */ ++#define WME_QI_STA_MAXSPLEN_MASK 0x60 /* Max Service Period Length mask */ ++#define WME_QI_STA_MAXSPLEN_SHIFT 5 /* Max Service Period Length shift */ ++#define WME_QI_STA_APSD_ALL_MASK 0xf /* APSD all AC bits mask */ ++#define WME_QI_STA_APSD_ALL_SHIFT 0 /* APSD all AC bits shift */ ++#define WME_QI_STA_APSD_BE_MASK 0x8 /* APSD AC_BE mask */ ++#define WME_QI_STA_APSD_BE_SHIFT 3 /* APSD AC_BE shift */ ++#define WME_QI_STA_APSD_BK_MASK 0x4 /* APSD AC_BK mask */ ++#define WME_QI_STA_APSD_BK_SHIFT 2 /* APSD AC_BK shift */ ++#define WME_QI_STA_APSD_VI_MASK 0x2 /* APSD AC_VI mask */ ++#define WME_QI_STA_APSD_VI_SHIFT 1 /* APSD AC_VI shift */ ++#define WME_QI_STA_APSD_VO_MASK 0x1 /* APSD AC_VO mask */ ++#define WME_QI_STA_APSD_VO_SHIFT 0 /* APSD AC_VO shift */ ++ ++/* ACI */ ++#define EDCF_AIFSN_MIN 1 /* AIFSN minimum value */ ++#define EDCF_AIFSN_MAX 15 /* AIFSN maximum value */ ++#define EDCF_AIFSN_MASK 0x0f /* AIFSN mask */ ++#define EDCF_ACM_MASK 0x10 /* ACM mask */ ++#define EDCF_ACI_MASK 0x60 /* ACI mask */ ++#define EDCF_ACI_SHIFT 5 /* ACI shift */ ++#define EDCF_AIFSN_SHIFT 12 /* 4 MSB(0xFFF) in ifs_ctl for AC idx */ ++ ++/* ECW */ ++#define EDCF_ECW_MIN 0 /* cwmin/cwmax exponent minimum value */ ++#define EDCF_ECW_MAX 15 /* cwmin/cwmax exponent maximum value */ ++#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1) ++#define EDCF_ECWMIN_MASK 0x0f /* cwmin exponent form mask */ ++#define EDCF_ECWMAX_MASK 0xf0 /* cwmax exponent form mask */ ++#define EDCF_ECWMAX_SHIFT 4 /* cwmax exponent form shift */ ++ ++/* TXOP */ ++#define EDCF_TXOP_MIN 0 /* TXOP minimum value */ ++#define EDCF_TXOP_MAX 65535 /* TXOP maximum value */ ++#define EDCF_TXOP2USEC(txop) ((txop) << 5) ++ ++/* Default BE ACI value for non-WME connection STA */ ++#define NON_EDCF_AC_BE_ACI_STA 0x02 ++ ++/* Default EDCF parameters that AP advertises for STA to use; WMM draft Table 12 */ ++#define EDCF_AC_BE_ACI_STA 0x03 /* STA ACI value for best effort AC */ ++#define EDCF_AC_BE_ECW_STA 0xA4 /* STA ECW value for best effort AC */ ++#define EDCF_AC_BE_TXOP_STA 0x0000 /* STA TXOP value for best effort AC */ ++#define EDCF_AC_BK_ACI_STA 0x27 /* STA ACI value for background AC */ ++#define EDCF_AC_BK_ECW_STA 0xA4 /* STA ECW value for background AC */ ++#define EDCF_AC_BK_TXOP_STA 0x0000 /* STA TXOP value for background AC */ ++#define EDCF_AC_VI_ACI_STA 0x42 /* STA ACI value for video AC */ ++#define EDCF_AC_VI_ECW_STA 0x43 /* STA ECW value for video AC */ ++#define EDCF_AC_VI_TXOP_STA 0x005e /* STA TXOP value for video AC */ ++#define EDCF_AC_VO_ACI_STA 0x62 /* STA ACI value for audio AC */ ++#define EDCF_AC_VO_ECW_STA 0x32 /* STA ECW value for audio AC */ ++#define EDCF_AC_VO_TXOP_STA 0x002f /* STA TXOP value for audio AC */ ++ ++/* Default EDCF parameters that AP uses; WMM draft Table 14 */ ++#define EDCF_AC_BE_ACI_AP 0x03 /* AP ACI value for best effort AC */ ++#define EDCF_AC_BE_ECW_AP 0x64 /* AP ECW value for best effort AC */ ++#define EDCF_AC_BE_TXOP_AP 0x0000 /* AP TXOP value for best effort AC */ ++#define EDCF_AC_BK_ACI_AP 0x27 /* AP ACI value for background AC */ ++#define EDCF_AC_BK_ECW_AP 0xA4 /* AP ECW value for background AC */ ++#define EDCF_AC_BK_TXOP_AP 0x0000 /* AP TXOP value for background AC */ ++#define EDCF_AC_VI_ACI_AP 0x41 /* AP ACI value for video AC */ ++#define EDCF_AC_VI_ECW_AP 0x43 /* AP ECW value for video AC */ ++#define EDCF_AC_VI_TXOP_AP 0x005e /* AP TXOP value for video AC */ ++#define EDCF_AC_VO_ACI_AP 0x61 /* AP ACI value for audio AC */ ++#define EDCF_AC_VO_ECW_AP 0x32 /* AP ECW value for audio AC */ ++#define EDCF_AC_VO_TXOP_AP 0x002f /* AP TXOP value for audio AC */ ++ ++/* EDCA Parameter IE */ ++BWL_PRE_PACKED_STRUCT struct edca_param_ie { ++ uint8 qosinfo; ++ uint8 rsvd; ++ edcf_acparam_t acparam[AC_COUNT]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct edca_param_ie edca_param_ie_t; ++#define EDCA_PARAM_IE_LEN 18 /* EDCA Parameter IE length */ ++ ++/* QoS Capability IE */ ++BWL_PRE_PACKED_STRUCT struct qos_cap_ie { ++ uint8 qosinfo; ++} BWL_POST_PACKED_STRUCT; ++typedef struct qos_cap_ie qos_cap_ie_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_qbss_load_ie { ++ uint8 id; /* 11, DOT11_MNG_QBSS_LOAD_ID */ ++ uint8 length; ++ uint16 station_count; /* total number of STAs associated */ ++ uint8 channel_utilization; /* % of time, normalized to 255, QAP sensed medium busy */ ++ uint16 aac; /* available admission capacity */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_qbss_load_ie dot11_qbss_load_ie_t; ++#define BSS_LOAD_IE_SIZE 7 /* BSS load IE size */ ++ ++/* nom_msdu_size */ ++#define FIXED_MSDU_SIZE 0x8000 /* MSDU size is fixed */ ++#define MSDU_SIZE_MASK 0x7fff /* (Nominal or fixed) MSDU size */ ++ ++/* surplus_bandwidth */ ++/* Represented as 3 bits of integer, binary point, 13 bits fraction */ ++#define INTEGER_SHIFT 13 /* integer shift */ ++#define FRACTION_MASK 0x1FFF /* fraction mask */ ++ ++/* Management Notification Frame */ ++BWL_PRE_PACKED_STRUCT struct dot11_management_notification { ++ uint8 category; /* DOT11_ACTION_NOTIFICATION */ ++ uint8 action; ++ uint8 token; ++ uint8 status; ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_MGMT_NOTIFICATION_LEN 4 /* Fixed length */ ++ ++/* Timeout Interval IE */ ++BWL_PRE_PACKED_STRUCT struct ti_ie { ++ uint8 ti_type; ++ uint32 ti_val; ++} BWL_POST_PACKED_STRUCT; ++typedef struct ti_ie ti_ie_t; ++#define TI_TYPE_REASSOC_DEADLINE 1 ++#define TI_TYPE_KEY_LIFETIME 2 ++ ++/* WME Action Codes */ ++#define WME_ADDTS_REQUEST 0 /* WME ADDTS request */ ++#define WME_ADDTS_RESPONSE 1 /* WME ADDTS response */ ++#define WME_DELTS_REQUEST 2 /* WME DELTS request */ ++ ++/* WME Setup Response Status Codes */ ++#define WME_ADMISSION_ACCEPTED 0 /* WME admission accepted */ ++#define WME_INVALID_PARAMETERS 1 /* WME invalide parameters */ ++#define WME_ADMISSION_REFUSED 3 /* WME admission refused */ ++ ++/* Macro to take a pointer to a beacon or probe response ++ * body and return the char* pointer to the SSID info element ++ */ ++#define BCN_PRB_SSID(body) ((char*)(body) + DOT11_BCN_PRB_LEN) ++ ++/* Authentication frame payload constants */ ++#define DOT11_OPEN_SYSTEM 0 /* d11 open authentication */ ++#define DOT11_SHARED_KEY 1 /* d11 shared authentication */ ++#define DOT11_FAST_BSS 2 /* d11 fast bss authentication */ ++#define DOT11_CHALLENGE_LEN 128 /* d11 challenge text length */ ++ ++/* Frame control macros */ ++#define FC_PVER_MASK 0x3 /* PVER mask */ ++#define FC_PVER_SHIFT 0 /* PVER shift */ ++#define FC_TYPE_MASK 0xC /* type mask */ ++#define FC_TYPE_SHIFT 2 /* type shift */ ++#define FC_SUBTYPE_MASK 0xF0 /* subtype mask */ ++#define FC_SUBTYPE_SHIFT 4 /* subtype shift */ ++#define FC_TODS 0x100 /* to DS */ ++#define FC_TODS_SHIFT 8 /* to DS shift */ ++#define FC_FROMDS 0x200 /* from DS */ ++#define FC_FROMDS_SHIFT 9 /* from DS shift */ ++#define FC_MOREFRAG 0x400 /* more frag. */ ++#define FC_MOREFRAG_SHIFT 10 /* more frag. shift */ ++#define FC_RETRY 0x800 /* retry */ ++#define FC_RETRY_SHIFT 11 /* retry shift */ ++#define FC_PM 0x1000 /* PM */ ++#define FC_PM_SHIFT 12 /* PM shift */ ++#define FC_MOREDATA 0x2000 /* more data */ ++#define FC_MOREDATA_SHIFT 13 /* more data shift */ ++#define FC_WEP 0x4000 /* WEP */ ++#define FC_WEP_SHIFT 14 /* WEP shift */ ++#define FC_ORDER 0x8000 /* order */ ++#define FC_ORDER_SHIFT 15 /* order shift */ ++ ++/* sequence control macros */ ++#define SEQNUM_SHIFT 4 /* seq. number shift */ ++#define SEQNUM_MAX 0x1000 /* max seqnum + 1 */ ++#define FRAGNUM_MASK 0xF /* frag. number mask */ ++ ++/* Frame Control type/subtype defs */ ++ ++/* FC Types */ ++#define FC_TYPE_MNG 0 /* management type */ ++#define FC_TYPE_CTL 1 /* control type */ ++#define FC_TYPE_DATA 2 /* data type */ ++ ++/* Management Subtypes */ ++#define FC_SUBTYPE_ASSOC_REQ 0 /* assoc. request */ ++#define FC_SUBTYPE_ASSOC_RESP 1 /* assoc. response */ ++#define FC_SUBTYPE_REASSOC_REQ 2 /* reassoc. request */ ++#define FC_SUBTYPE_REASSOC_RESP 3 /* reassoc. response */ ++#define FC_SUBTYPE_PROBE_REQ 4 /* probe request */ ++#define FC_SUBTYPE_PROBE_RESP 5 /* probe response */ ++#define FC_SUBTYPE_BEACON 8 /* beacon */ ++#define FC_SUBTYPE_ATIM 9 /* ATIM */ ++#define FC_SUBTYPE_DISASSOC 10 /* disassoc. */ ++#define FC_SUBTYPE_AUTH 11 /* authentication */ ++#define FC_SUBTYPE_DEAUTH 12 /* de-authentication */ ++#define FC_SUBTYPE_ACTION 13 /* action */ ++#define FC_SUBTYPE_ACTION_NOACK 14 /* action no-ack */ ++ ++/* Control Subtypes */ ++#define FC_SUBTYPE_CTL_WRAPPER 7 /* Control Wrapper */ ++#define FC_SUBTYPE_BLOCKACK_REQ 8 /* Block Ack Req */ ++#define FC_SUBTYPE_BLOCKACK 9 /* Block Ack */ ++#define FC_SUBTYPE_PS_POLL 10 /* PS poll */ ++#define FC_SUBTYPE_RTS 11 /* RTS */ ++#define FC_SUBTYPE_CTS 12 /* CTS */ ++#define FC_SUBTYPE_ACK 13 /* ACK */ ++#define FC_SUBTYPE_CF_END 14 /* CF-END */ ++#define FC_SUBTYPE_CF_END_ACK 15 /* CF-END ACK */ ++ ++/* Data Subtypes */ ++#define FC_SUBTYPE_DATA 0 /* Data */ ++#define FC_SUBTYPE_DATA_CF_ACK 1 /* Data + CF-ACK */ ++#define FC_SUBTYPE_DATA_CF_POLL 2 /* Data + CF-Poll */ ++#define FC_SUBTYPE_DATA_CF_ACK_POLL 3 /* Data + CF-Ack + CF-Poll */ ++#define FC_SUBTYPE_NULL 4 /* Null */ ++#define FC_SUBTYPE_CF_ACK 5 /* CF-Ack */ ++#define FC_SUBTYPE_CF_POLL 6 /* CF-Poll */ ++#define FC_SUBTYPE_CF_ACK_POLL 7 /* CF-Ack + CF-Poll */ ++#define FC_SUBTYPE_QOS_DATA 8 /* QoS Data */ ++#define FC_SUBTYPE_QOS_DATA_CF_ACK 9 /* QoS Data + CF-Ack */ ++#define FC_SUBTYPE_QOS_DATA_CF_POLL 10 /* QoS Data + CF-Poll */ ++#define FC_SUBTYPE_QOS_DATA_CF_ACK_POLL 11 /* QoS Data + CF-Ack + CF-Poll */ ++#define FC_SUBTYPE_QOS_NULL 12 /* QoS Null */ ++#define FC_SUBTYPE_QOS_CF_POLL 14 /* QoS CF-Poll */ ++#define FC_SUBTYPE_QOS_CF_ACK_POLL 15 /* QoS CF-Ack + CF-Poll */ ++ ++/* Data Subtype Groups */ ++#define FC_SUBTYPE_ANY_QOS(s) (((s) & 8) != 0) ++#define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0) ++#define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0) ++#define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0) ++ ++/* Type/Subtype Combos */ ++#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK) /* FC kind mask */ ++ ++#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT)) /* FC kind */ ++ ++#define FC_SUBTYPE(fc) (((fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT) /* Subtype from FC */ ++#define FC_TYPE(fc) (((fc) & FC_TYPE_MASK) >> FC_TYPE_SHIFT) /* Type from FC */ ++ ++#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ) /* assoc. request */ ++#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP) /* assoc. response */ ++#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ) /* reassoc. request */ ++#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP) /* reassoc. response */ ++#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ) /* probe request */ ++#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP) /* probe response */ ++#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON) /* beacon */ ++#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC) /* disassoc */ ++#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH) /* authentication */ ++#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH) /* deauthentication */ ++#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION) /* action */ ++#define FC_ACTION_NOACK FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION_NOACK) /* action no-ack */ ++ ++#define FC_CTL_WRAPPER FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTL_WRAPPER) /* Control Wrapper */ ++#define FC_BLOCKACK_REQ FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK_REQ) /* Block Ack Req */ ++#define FC_BLOCKACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK) /* Block Ack */ ++#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL) /* PS poll */ ++#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS) /* RTS */ ++#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS) /* CTS */ ++#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK) /* ACK */ ++#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END) /* CF-END */ ++#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK) /* CF-END ACK */ ++ ++#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA) /* data */ ++#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL) /* null data */ ++#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK) /* data CF ACK */ ++#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA) /* QoS data */ ++#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL) /* QoS null */ ++ ++/* QoS Control Field */ ++ ++/* 802.1D Priority */ ++#define QOS_PRIO_SHIFT 0 /* QoS priority shift */ ++#define QOS_PRIO_MASK 0x0007 /* QoS priority mask */ ++#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT) /* QoS priority */ ++ ++/* Traffic Identifier */ ++#define QOS_TID_SHIFT 0 /* QoS TID shift */ ++#define QOS_TID_MASK 0x000f /* QoS TID mask */ ++#define QOS_TID(qos) (((qos) & QOS_TID_MASK) >> QOS_TID_SHIFT) /* QoS TID */ ++ ++/* End of Service Period (U-APSD) */ ++#define QOS_EOSP_SHIFT 4 /* QoS End of Service Period shift */ ++#define QOS_EOSP_MASK 0x0010 /* QoS End of Service Period mask */ ++#define QOS_EOSP(qos) (((qos) & QOS_EOSP_MASK) >> QOS_EOSP_SHIFT) /* Qos EOSP */ ++ ++/* Ack Policy */ ++#define QOS_ACK_NORMAL_ACK 0 /* Normal Ack */ ++#define QOS_ACK_NO_ACK 1 /* No Ack (eg mcast) */ ++#define QOS_ACK_NO_EXP_ACK 2 /* No Explicit Ack */ ++#define QOS_ACK_BLOCK_ACK 3 /* Block Ack */ ++#define QOS_ACK_SHIFT 5 /* QoS ACK shift */ ++#define QOS_ACK_MASK 0x0060 /* QoS ACK mask */ ++#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT) /* QoS ACK */ ++ ++/* A-MSDU flag */ ++#define QOS_AMSDU_SHIFT 7 /* AMSDU shift */ ++#define QOS_AMSDU_MASK 0x0080 /* AMSDU mask */ ++ ++/* Management Frames */ ++ ++/* Management Frame Constants */ ++ ++/* Fixed fields */ ++#define DOT11_MNG_AUTH_ALGO_LEN 2 /* d11 management auth. algo. length */ ++#define DOT11_MNG_AUTH_SEQ_LEN 2 /* d11 management auth. seq. length */ ++#define DOT11_MNG_BEACON_INT_LEN 2 /* d11 management beacon interval length */ ++#define DOT11_MNG_CAP_LEN 2 /* d11 management cap. length */ ++#define DOT11_MNG_AP_ADDR_LEN 6 /* d11 management AP address length */ ++#define DOT11_MNG_LISTEN_INT_LEN 2 /* d11 management listen interval length */ ++#define DOT11_MNG_REASON_LEN 2 /* d11 management reason length */ ++#define DOT11_MNG_AID_LEN 2 /* d11 management AID length */ ++#define DOT11_MNG_STATUS_LEN 2 /* d11 management status length */ ++#define DOT11_MNG_TIMESTAMP_LEN 8 /* d11 management timestamp length */ ++ ++/* DUR/ID field in assoc resp is 0xc000 | AID */ ++#define DOT11_AID_MASK 0x3fff /* d11 AID mask */ ++ ++/* Reason Codes */ ++#define DOT11_RC_RESERVED 0 /* d11 RC reserved */ ++#define DOT11_RC_UNSPECIFIED 1 /* Unspecified reason */ ++#define DOT11_RC_AUTH_INVAL 2 /* Previous authentication no longer valid */ ++#define DOT11_RC_DEAUTH_LEAVING 3 /* Deauthenticated because sending station ++ * is leaving (or has left) IBSS or ESS ++ */ ++#define DOT11_RC_INACTIVITY 4 /* Disassociated due to inactivity */ ++#define DOT11_RC_BUSY 5 /* Disassociated because AP is unable to handle ++ * all currently associated stations ++ */ ++#define DOT11_RC_INVAL_CLASS_2 6 /* Class 2 frame received from ++ * nonauthenticated station ++ */ ++#define DOT11_RC_INVAL_CLASS_3 7 /* Class 3 frame received from ++ * nonassociated station ++ */ ++#define DOT11_RC_DISASSOC_LEAVING 8 /* Disassociated because sending station is ++ * leaving (or has left) BSS ++ */ ++#define DOT11_RC_NOT_AUTH 9 /* Station requesting (re)association is not ++ * authenticated with responding station ++ */ ++#define DOT11_RC_BAD_PC 10 /* Unacceptable power capability element */ ++#define DOT11_RC_BAD_CHANNELS 11 /* Unacceptable supported channels element */ ++/* 12 is unused */ ++ ++/* 32-39 are QSTA specific reasons added in 11e */ ++#define DOT11_RC_UNSPECIFIED_QOS 32 /* unspecified QoS-related reason */ ++#define DOT11_RC_INSUFFCIENT_BW 33 /* QAP lacks sufficient bandwidth */ ++#define DOT11_RC_EXCESSIVE_FRAMES 34 /* excessive number of frames need ack */ ++#define DOT11_RC_TX_OUTSIDE_TXOP 35 /* transmitting outside the limits of txop */ ++#define DOT11_RC_LEAVING_QBSS 36 /* QSTA is leaving the QBSS (or restting) */ ++#define DOT11_RC_BAD_MECHANISM 37 /* does not want to use the mechanism */ ++#define DOT11_RC_SETUP_NEEDED 38 /* mechanism needs a setup */ ++#define DOT11_RC_TIMEOUT 39 /* timeout */ ++ ++#define DOT11_RC_MAX 23 /* Reason codes > 23 are reserved */ ++ ++#define DOT11_RC_TDLS_PEER_UNREACH 25 ++#define DOT11_RC_TDLS_DOWN_UNSPECIFIED 26 ++ ++/* Status Codes */ ++#define DOT11_SC_SUCCESS 0 /* Successful */ ++#define DOT11_SC_FAILURE 1 /* Unspecified failure */ ++#define DOT11_SC_TDLS_WAKEUP_SCH_ALT 2 /* TDLS wakeup schedule rejected but alternative */ ++ /* schedule provided */ ++#define DOT11_SC_TDLS_WAKEUP_SCH_REJ 3 /* TDLS wakeup schedule rejected */ ++#define DOT11_SC_TDLS_SEC_DISABLED 5 /* TDLS Security disabled */ ++#define DOT11_SC_LIFETIME_REJ 6 /* Unacceptable lifetime */ ++#define DOT11_SC_NOT_SAME_BSS 7 /* Not in same BSS */ ++#define DOT11_SC_CAP_MISMATCH 10 /* Cannot support all requested ++ * capabilities in the Capability ++ * Information field ++ */ ++#define DOT11_SC_REASSOC_FAIL 11 /* Reassociation denied due to inability ++ * to confirm that association exists ++ */ ++#define DOT11_SC_ASSOC_FAIL 12 /* Association denied due to reason ++ * outside the scope of this standard ++ */ ++#define DOT11_SC_AUTH_MISMATCH 13 /* Responding station does not support ++ * the specified authentication ++ * algorithm ++ */ ++#define DOT11_SC_AUTH_SEQ 14 /* Received an Authentication frame ++ * with authentication transaction ++ * sequence number out of expected ++ * sequence ++ */ ++#define DOT11_SC_AUTH_CHALLENGE_FAIL 15 /* Authentication rejected because of ++ * challenge failure ++ */ ++#define DOT11_SC_AUTH_TIMEOUT 16 /* Authentication rejected due to timeout ++ * waiting for next frame in sequence ++ */ ++#define DOT11_SC_ASSOC_BUSY_FAIL 17 /* Association denied because AP is ++ * unable to handle additional ++ * associated stations ++ */ ++#define DOT11_SC_ASSOC_RATE_MISMATCH 18 /* Association denied due to requesting ++ * station not supporting all of the ++ * data rates in the BSSBasicRateSet ++ * parameter ++ */ ++#define DOT11_SC_ASSOC_SHORT_REQUIRED 19 /* Association denied due to requesting ++ * station not supporting the Short ++ * Preamble option ++ */ ++#define DOT11_SC_ASSOC_PBCC_REQUIRED 20 /* Association denied due to requesting ++ * station not supporting the PBCC ++ * Modulation option ++ */ ++#define DOT11_SC_ASSOC_AGILITY_REQUIRED 21 /* Association denied due to requesting ++ * station not supporting the Channel ++ * Agility option ++ */ ++#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22 /* Association denied because Spectrum ++ * Management capability is required. ++ */ ++#define DOT11_SC_ASSOC_BAD_POWER_CAP 23 /* Association denied because the info ++ * in the Power Cap element is ++ * unacceptable. ++ */ ++#define DOT11_SC_ASSOC_BAD_SUP_CHANNELS 24 /* Association denied because the info ++ * in the Supported Channel element is ++ * unacceptable ++ */ ++#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 /* Association denied due to requesting ++ * station not supporting the Short Slot ++ * Time option ++ */ ++#define DOT11_SC_ASSOC_ERPBCC_REQUIRED 26 /* Association denied due to requesting ++ * station not supporting the ER-PBCC ++ * Modulation option ++ */ ++#define DOT11_SC_ASSOC_DSSOFDM_REQUIRED 27 /* Association denied due to requesting ++ * station not supporting the DSS-OFDM ++ * option ++ */ ++#define DOT11_SC_ASSOC_R0KH_UNREACHABLE 28 /* Association denied due to AP ++ * being unable to reach the R0 Key Holder ++ */ ++#define DOT11_SC_ASSOC_TRY_LATER 30 /* Association denied temporarily, try again later ++ */ ++#define DOT11_SC_ASSOC_MFP_VIOLATION 31 /* Association denied due to Robust Management ++ * frame policy violation ++ */ ++ ++#define DOT11_SC_DECLINED 37 /* request declined */ ++#define DOT11_SC_INVALID_PARAMS 38 /* One or more params have invalid values */ ++#define DOT11_SC_INVALID_PAIRWISE_CIPHER 42 /* invalid pairwise cipher */ ++#define DOT11_SC_INVALID_AKMP 43 /* Association denied due to invalid AKMP */ ++#define DOT11_SC_INVALID_RSNIE_CAP 45 /* invalid RSN IE capabilities */ ++#define DOT11_SC_DLS_NOT_ALLOWED 48 /* DLS is not allowed in the BSS by policy */ ++#define DOT11_SC_INVALID_PMKID 53 /* Association denied due to invalid PMKID */ ++#define DOT11_SC_INVALID_MDID 54 /* Association denied due to invalid MDID */ ++#define DOT11_SC_INVALID_FTIE 55 /* Association denied due to invalid FTIE */ ++ ++#define DOT11_SC_UNEXP_MSG 70 /* Unexpected message */ ++#define DOT11_SC_INVALID_SNONCE 71 /* Invalid SNonce */ ++#define DOT11_SC_INVALID_RSNIE 72 /* Invalid contents of RSNIE */ ++ ++/* Info Elts, length of INFORMATION portion of Info Elts */ ++#define DOT11_MNG_DS_PARAM_LEN 1 /* d11 management DS parameter length */ ++#define DOT11_MNG_IBSS_PARAM_LEN 2 /* d11 management IBSS parameter length */ ++ ++/* TIM Info element has 3 bytes fixed info in INFORMATION field, ++ * followed by 1 to 251 bytes of Partial Virtual Bitmap ++ */ ++#define DOT11_MNG_TIM_FIXED_LEN 3 /* d11 management TIM fixed length */ ++#define DOT11_MNG_TIM_DTIM_COUNT 0 /* d11 management DTIM count */ ++#define DOT11_MNG_TIM_DTIM_PERIOD 1 /* d11 management DTIM period */ ++#define DOT11_MNG_TIM_BITMAP_CTL 2 /* d11 management TIM BITMAP control */ ++#define DOT11_MNG_TIM_PVB 3 /* d11 management TIM PVB */ ++ ++/* TLV defines */ ++#define TLV_TAG_OFF 0 /* tag offset */ ++#define TLV_LEN_OFF 1 /* length offset */ ++#define TLV_HDR_LEN 2 /* header length */ ++#define TLV_BODY_OFF 2 /* body offset */ ++ ++/* Management Frame Information Element IDs */ ++#define DOT11_MNG_SSID_ID 0 /* d11 management SSID id */ ++#define DOT11_MNG_RATES_ID 1 /* d11 management rates id */ ++#define DOT11_MNG_FH_PARMS_ID 2 /* d11 management FH parameter id */ ++#define DOT11_MNG_DS_PARMS_ID 3 /* d11 management DS parameter id */ ++#define DOT11_MNG_CF_PARMS_ID 4 /* d11 management CF parameter id */ ++#define DOT11_MNG_TIM_ID 5 /* d11 management TIM id */ ++#define DOT11_MNG_IBSS_PARMS_ID 6 /* d11 management IBSS parameter id */ ++#define DOT11_MNG_COUNTRY_ID 7 /* d11 management country id */ ++#define DOT11_MNG_HOPPING_PARMS_ID 8 /* d11 management hopping parameter id */ ++#define DOT11_MNG_HOPPING_TABLE_ID 9 /* d11 management hopping table id */ ++#define DOT11_MNG_REQUEST_ID 10 /* d11 management request id */ ++#define DOT11_MNG_QBSS_LOAD_ID 11 /* d11 management QBSS Load id */ ++#define DOT11_MNG_EDCA_PARAM_ID 12 /* 11E EDCA Parameter id */ ++#define DOT11_MNG_CHALLENGE_ID 16 /* d11 management chanllenge id */ ++#define DOT11_MNG_PWR_CONSTRAINT_ID 32 /* 11H PowerConstraint */ ++#define DOT11_MNG_PWR_CAP_ID 33 /* 11H PowerCapability */ ++#define DOT11_MNG_TPC_REQUEST_ID 34 /* 11H TPC Request */ ++#define DOT11_MNG_TPC_REPORT_ID 35 /* 11H TPC Report */ ++#define DOT11_MNG_SUPP_CHANNELS_ID 36 /* 11H Supported Channels */ ++#define DOT11_MNG_CHANNEL_SWITCH_ID 37 /* 11H ChannelSwitch Announcement */ ++#define DOT11_MNG_MEASURE_REQUEST_ID 38 /* 11H MeasurementRequest */ ++#define DOT11_MNG_MEASURE_REPORT_ID 39 /* 11H MeasurementReport */ ++#define DOT11_MNG_QUIET_ID 40 /* 11H Quiet */ ++#define DOT11_MNG_IBSS_DFS_ID 41 /* 11H IBSS_DFS */ ++#define DOT11_MNG_ERP_ID 42 /* d11 management ERP id */ ++#define DOT11_MNG_TS_DELAY_ID 43 /* d11 management TS Delay id */ ++#define DOT11_MNG_HT_CAP 45 /* d11 mgmt HT cap id */ ++#define DOT11_MNG_QOS_CAP_ID 46 /* 11E QoS Capability id */ ++#define DOT11_MNG_NONERP_ID 47 /* d11 management NON-ERP id */ ++#define DOT11_MNG_RSN_ID 48 /* d11 management RSN id */ ++#define DOT11_MNG_EXT_RATES_ID 50 /* d11 management ext. rates id */ ++#define DOT11_MNG_AP_CHREP_ID 51 /* 11k AP Channel report id */ ++#define DOT11_MNG_NBR_REP_ID 52 /* 11k Neighbor report id */ ++#define DOT11_MNG_MDIE_ID 54 /* 11r Mobility domain id */ ++#define DOT11_MNG_FTIE_ID 55 /* 11r Fast Bss Transition id */ ++#define DOT11_MNG_FT_TI_ID 56 /* 11r Timeout Interval id */ ++#define DOT11_MNG_REGCLASS_ID 59 /* d11 management regulatory class id */ ++#define DOT11_MNG_EXT_CSA_ID 60 /* d11 Extended CSA */ ++#define DOT11_MNG_HT_ADD 61 /* d11 mgmt additional HT info */ ++#define DOT11_MNG_EXT_CHANNEL_OFFSET 62 /* d11 mgmt ext channel offset */ ++#ifdef BCMWAPI_WAI ++#define DOT11_MNG_WAPI_ID 68 /* d11 management WAPI id */ ++#endif ++#define DOT11_MNG_WAPI_ID 68 /* d11 management WAPI id */ ++#define DOT11_MNG_TIME_ADVERTISE_ID 69 /* 11p time advertisement */ ++#define DOT11_MNG_RRM_CAP_ID 70 /* 11k radio measurement capability */ ++#define DOT11_MNG_HT_BSS_COEXINFO_ID 72 /* d11 mgmt OBSS Coexistence INFO */ ++#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73 /* d11 mgmt OBSS Intolerant Channel list */ ++#define DOT11_MNG_HT_OBSS_ID 74 /* d11 mgmt OBSS HT info */ ++#define DOT11_MNG_CHANNEL_USAGE 97 /* 11v channel usage */ ++#define DOT11_MNG_TIME_ZONE_ID 98 /* 11v time zone */ ++#define DOT11_MNG_LINK_IDENTIFIER_ID 101 /* 11z TDLS Link Identifier IE */ ++#define DOT11_MNG_WAKEUP_SCHEDULE_ID 102 /* 11z TDLS Wakeup Schedule IE */ ++#define DOT11_MNG_CHANNEL_SWITCH_TIMING_ID 104 /* 11z TDLS Channel Switch Timing IE */ ++#define DOT11_MNG_PTI_CONTROL_ID 105 /* 11z TDLS PTI Control IE */ ++#define DOT11_MNG_PU_BUFFER_STATUS_ID 106 /* 11z TDLS PU Buffer Status IE */ ++#define DOT11_MNG_INTERWORKING_ID 107 /* 11u interworking */ ++#define DOT11_MNG_ADVERTISEMENT_ID 108 /* 11u advertisement protocol */ ++#define DOT11_MNG_EXP_BW_REQ_ID 109 /* 11u expedited bandwith request */ ++#define DOT11_MNG_QOS_MAP_ID 110 /* 11u QoS map set */ ++#define DOT11_MNG_ROAM_CONSORT_ID 111 /* 11u roaming consortium */ ++#define DOT11_MNG_EMERGCY_ALERT_ID 112 /* 11u emergency alert identifier */ ++#define DOT11_MNG_EXT_CAP_ID 127 /* d11 mgmt ext capability */ ++#define DOT11_MNG_VHT_CAP_ID 191 /* d11 mgmt VHT cap id */ ++#define DOT11_MNG_VHT_OPERATION_ID 192 /* d11 mgmt VHT op id */ ++ ++#define DOT11_MNG_WPA_ID 221 /* d11 management WPA id */ ++#define DOT11_MNG_PROPR_ID 221 /* d11 management proprietary id */ ++/* should start using this one instead of above two */ ++#define DOT11_MNG_VS_ID 221 /* d11 management Vendor Specific IE */ ++ ++/* Rate element Basic flag and rate mask */ ++#define DOT11_RATE_BASIC 0x80 /* flag for a Basic Rate */ ++#define DOT11_RATE_MASK 0x7F /* mask for numeric part of rate */ ++ ++/* ERP info element bit values */ ++#define DOT11_MNG_ERP_LEN 1 /* ERP is currently 1 byte long */ ++#define DOT11_MNG_NONERP_PRESENT 0x01 /* NonERP (802.11b) STAs are present ++ *in the BSS ++ */ ++#define DOT11_MNG_USE_PROTECTION 0x02 /* Use protection mechanisms for ++ *ERP-OFDM frames ++ */ ++#define DOT11_MNG_BARKER_PREAMBLE 0x04 /* Short Preambles: 0 == allowed, ++ * 1 == not allowed ++ */ ++/* TS Delay element offset & size */ ++#define DOT11_MGN_TS_DELAY_LEN 4 /* length of TS DELAY IE */ ++#define TS_DELAY_FIELD_SIZE 4 /* TS DELAY field size */ ++ ++/* Capability Information Field */ ++#define DOT11_CAP_ESS 0x0001 /* d11 cap. ESS */ ++#define DOT11_CAP_IBSS 0x0002 /* d11 cap. IBSS */ ++#define DOT11_CAP_POLLABLE 0x0004 /* d11 cap. pollable */ ++#define DOT11_CAP_POLL_RQ 0x0008 /* d11 cap. poll request */ ++#define DOT11_CAP_PRIVACY 0x0010 /* d11 cap. privacy */ ++#define DOT11_CAP_SHORT 0x0020 /* d11 cap. short */ ++#define DOT11_CAP_PBCC 0x0040 /* d11 cap. PBCC */ ++#define DOT11_CAP_AGILITY 0x0080 /* d11 cap. agility */ ++#define DOT11_CAP_SPECTRUM 0x0100 /* d11 cap. spectrum */ ++#define DOT11_CAP_SHORTSLOT 0x0400 /* d11 cap. shortslot */ ++#define DOT11_CAP_RRM 0x1000 /* d11 cap. 11k radio measurement */ ++#define DOT11_CAP_CCK_OFDM 0x2000 /* d11 cap. CCK/OFDM */ ++ ++/* Extended capabilities IE bitfields */ ++/* 20/40 BSS Coexistence Management support bit position */ ++#define DOT11_EXT_CAP_OBSS_COEX_MGMT 0 ++/* scheduled PSMP support bit position */ ++#define DOT11_EXT_CAP_SPSMP 6 ++/* BSS Transition Management support bit position */ ++#define DOT11_EXT_CAP_BSS_TRANSITION_MGMT 19 ++/* Interworking support bit position */ ++#define DOT11_EXT_CAP_IW 31 ++/* service Interval granularity bit position and mask */ ++#define DOT11_EXT_CAP_SI 41 ++#define DOT11_EXT_CAP_SI_MASK 0x0E ++ ++/* ++ * Action Frame Constants ++ */ ++#define DOT11_ACTION_HDR_LEN 2 /* action frame category + action field */ ++#define DOT11_ACTION_CAT_OFF 0 /* category offset */ ++#define DOT11_ACTION_ACT_OFF 1 /* action offset */ ++ ++/* Action Category field (sec 7.3.1.11) */ ++#define DOT11_ACTION_CAT_ERR_MASK 0x80 /* category error mask */ ++#define DOT11_ACTION_CAT_MASK 0x7F /* category mask */ ++#define DOT11_ACTION_CAT_SPECT_MNG 0 /* category spectrum management */ ++#define DOT11_ACTION_CAT_QOS 1 /* category QoS */ ++#define DOT11_ACTION_CAT_DLS 2 /* category DLS */ ++#define DOT11_ACTION_CAT_BLOCKACK 3 /* category block ack */ ++#define DOT11_ACTION_CAT_PUBLIC 4 /* category public */ ++#define DOT11_ACTION_CAT_RRM 5 /* category radio measurements */ ++#define DOT11_ACTION_CAT_FBT 6 /* category fast bss transition */ ++#define DOT11_ACTION_CAT_HT 7 /* category for HT */ ++#define DOT11_ACTION_CAT_SA_QUERY 8 /* security association query */ ++#define DOT11_ACTION_CAT_PDPA 9 /* protected dual of public action */ ++#define DOT11_ACTION_CAT_BSSMGMT 10 /* category for BSS transition management */ ++#define DOT11_ACTION_NOTIFICATION 17 ++#define DOT11_ACTION_CAT_VSP 126 /* protected vendor specific */ ++#define DOT11_ACTION_CAT_VS 127 /* category Vendor Specific */ ++ ++/* Spectrum Management Action IDs (sec 7.4.1) */ ++#define DOT11_SM_ACTION_M_REQ 0 /* d11 action measurement request */ ++#define DOT11_SM_ACTION_M_REP 1 /* d11 action measurement response */ ++#define DOT11_SM_ACTION_TPC_REQ 2 /* d11 action TPC request */ ++#define DOT11_SM_ACTION_TPC_REP 3 /* d11 action TPC response */ ++#define DOT11_SM_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */ ++#define DOT11_SM_ACTION_EXT_CSA 5 /* d11 extened CSA for 11n */ ++ ++/* HT action ids */ ++#define DOT11_ACTION_ID_HT_CH_WIDTH 0 /* notify channel width action id */ ++#define DOT11_ACTION_ID_HT_MIMO_PS 1 /* mimo ps action id */ ++ ++/* Public action ids */ ++#define DOT11_PUB_ACTION_BSS_COEX_MNG 0 /* 20/40 Coexistence Management action id */ ++#define DOT11_PUB_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */ ++ ++/* Block Ack action types */ ++#define DOT11_BA_ACTION_ADDBA_REQ 0 /* ADDBA Req action frame type */ ++#define DOT11_BA_ACTION_ADDBA_RESP 1 /* ADDBA Resp action frame type */ ++#define DOT11_BA_ACTION_DELBA 2 /* DELBA action frame type */ ++ ++/* ADDBA action parameters */ ++#define DOT11_ADDBA_PARAM_AMSDU_SUP 0x0001 /* AMSDU supported under BA */ ++#define DOT11_ADDBA_PARAM_POLICY_MASK 0x0002 /* policy mask(ack vs delayed) */ ++#define DOT11_ADDBA_PARAM_POLICY_SHIFT 1 /* policy shift */ ++#define DOT11_ADDBA_PARAM_TID_MASK 0x003c /* tid mask */ ++#define DOT11_ADDBA_PARAM_TID_SHIFT 2 /* tid shift */ ++#define DOT11_ADDBA_PARAM_BSIZE_MASK 0xffc0 /* buffer size mask */ ++#define DOT11_ADDBA_PARAM_BSIZE_SHIFT 6 /* buffer size shift */ ++ ++#define DOT11_ADDBA_POLICY_DELAYED 0 /* delayed BA policy */ ++#define DOT11_ADDBA_POLICY_IMMEDIATE 1 /* immediate BA policy */ ++ ++/* Fast Transition action types */ ++#define DOT11_FT_ACTION_FT_RESERVED 0 ++#define DOT11_FT_ACTION_FT_REQ 1 /* FBT request - for over-the-DS FBT */ ++#define DOT11_FT_ACTION_FT_RES 2 /* FBT response - for over-the-DS FBT */ ++#define DOT11_FT_ACTION_FT_CON 3 /* FBT confirm - for OTDS with RRP */ ++#define DOT11_FT_ACTION_FT_ACK 4 /* FBT ack */ ++ ++/* DLS action types */ ++#define DOT11_DLS_ACTION_REQ 0 /* DLS Request */ ++#define DOT11_DLS_ACTION_RESP 1 /* DLS Response */ ++#define DOT11_DLS_ACTION_TD 2 /* DLS Teardown */ ++ ++/* Wireless Network Management (WNM) action types */ ++#define DOT11_WNM_ACTION_EVENT_REQ 0 ++#define DOT11_WNM_ACTION_EVENT_REP 1 ++#define DOT11_WNM_ACTION_DIAG_REQ 2 ++#define DOT11_WNM_ACTION_DIAG_REP 3 ++#define DOT11_WNM_ACTION_LOC_CFG_REQ 4 ++#define DOT11_WNM_ACTION_LOC_RFG_RESP 5 ++#define DOT11_WNM_ACTION_BSS_TRANS_QURY 6 ++#define DOT11_WNM_ACTION_BSS_TRANS_REQ 7 ++#define DOT11_WNM_ACTION_BSS_TRANS_RESP 8 ++#define DOT11_WNM_ACTION_FMS_REQ 9 ++#define DOT11_WNM_ACTION_FMS_RESP 10 ++#define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ 11 ++#define DOT11_WNM_ACTION_COL_INTRFRNCE_REP 12 ++#define DOT11_WNM_ACTION_TFS_REQ 13 ++#define DOT11_WNM_ACTION_TFS_RESP 14 ++#define DOT11_WNM_ACTION_TFS_NOTIFY 15 ++#define DOT11_WNM_ACTION_WNM_SLEEP_REQ 16 ++#define DOT11_WNM_ACTION_WNM_SLEEP_RESP 17 ++#define DOT11_WNM_ACTION_TIM_BCAST_REQ 18 ++#define DOT11_WNM_ACTION_TIM_BCAST_RESP 19 ++#define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD 20 ++#define DOT11_WNM_ACTION_CHAN_USAGE_REQ 21 ++#define DOT11_WNM_ACTION_CHAN_USAGE_RESP 22 ++#define DOT11_WNM_ACTION_DMS_REQ 23 ++#define DOT11_WNM_ACTION_DMS_RESP 24 ++#define DOT11_WNM_ACTION_TMNG_MEASUR_REQ 25 ++#define DOT11_WNM_ACTION_NOTFCTN_REQ 26 ++#define DOT11_WNM_ACTION_NOTFCTN_RES 27 ++ ++#define DOT11_MNG_COUNTRY_ID_LEN 3 ++ ++/* DLS Request frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_dls_req { ++ uint8 category; /* category of action frame (2) */ ++ uint8 action; /* DLS action: req (0) */ ++ struct ether_addr da; /* destination address */ ++ struct ether_addr sa; /* source address */ ++ uint16 cap; /* capability */ ++ uint16 timeout; /* timeout value */ ++ uint8 data[1]; /* IE:support rate, extend support rate, HT cap */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_dls_req dot11_dls_req_t; ++#define DOT11_DLS_REQ_LEN 18 /* Fixed length */ ++ ++/* DLS response frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_dls_resp { ++ uint8 category; /* category of action frame (2) */ ++ uint8 action; /* DLS action: req (0) */ ++ uint16 status; /* status code field */ ++ struct ether_addr da; /* destination address */ ++ struct ether_addr sa; /* source address */ ++ uint8 data[1]; /* optional: capability, rate ... */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_dls_resp dot11_dls_resp_t; ++#define DOT11_DLS_RESP_LEN 16 /* Fixed length */ ++ ++ ++/* BSS Management Transition Query frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_query { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: trans_query (6) */ ++ uint8 token; /* dialog token */ ++ uint8 reason; /* transition query reason */ ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_bss_trans_query dot11_bss_trans_query_t; ++#define DOT11_BSS_TRANS_QUERY_LEN 4 /* Fixed length */ ++ ++/* BSS Management Transition Request frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_req { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: trans_req (7) */ ++ uint8 token; /* dialog token */ ++ uint8 reqmode; /* transition request mode */ ++ uint16 disassoc_tmr; /* disassociation timer */ ++ uint8 validity_intrvl; /* validity interval */ ++ uint8 data[1]; /* optional: BSS term duration, ... */ ++ /* ...session info URL, list */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_bss_trans_req dot11_bss_trans_req_t; ++#define DOT11_BSS_TRANS_REQ_LEN 7 /* Fixed length */ ++ ++#define DOT11_BSS_TERM_DUR_LEN 12 /* Fixed length if present */ ++ ++ ++/* BSS Mgmt Transition Request Mode Field - 802.11v */ ++#define DOT11_BSS_TRNS_REQMODE_PREF_LIST_INCL 0x01 ++#define DOT11_BSS_TRNS_REQMODE_ABRIDGED 0x02 ++#define DOT11_BSS_TRNS_REQMODE_DISASSOC_IMMINENT 0x04 ++#define DOT11_BSS_TRNS_REQMODE_BSS_TERM_INCL 0x08 ++#define DOT11_BSS_TRNS_REQMODE_ESS_DISASSOC_IMNT 0x10 ++ ++ ++/* BSS Management transition response frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_res { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: trans_res (8) */ ++ uint8 token; /* dialog token */ ++ uint8 status; /* transition status */ ++ uint8 term_delay; /* validity interval */ ++ uint8 data[1]; /* optional: BSS term duration, ... */ ++ /* ...session info URL, list */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_bss_trans_res dot11_bss_trans_res_t; ++#define DOT11_BSS_TRANS_RES_LEN 5 /* Fixed length */ ++ ++/* BSS Mgmt Transition Response Status Field */ ++#define DOT11_BSS_TRNS_RES_STATUS_ACCEPT 0 ++#define DOT11_BSS_TRNS_RES_STATUS_REJECT 1 ++#define DOT11_BSS_TRNS_RES_STATUS_REJ_INSUFF_BCN 2 ++#define DOT11_BSS_TRNS_RES_STATUS_REJ_INSUFF_CAP 3 ++#define DOT11_BSS_TRNS_RES_STATUS_REJ_TERM_UNDESIRED 4 ++#define DOT11_BSS_TRNS_RES_STATUS_REJ_TERM_DELAY_REQ 5 ++#define DOT11_BSS_TRNS_RES_STATUS_REJ_BSS_LIST_PROVIDED 6 ++#define DOT11_BSS_TRNS_RES_STATUS_REJ_NO_SUITABLE_BSS 7 ++#define DOT11_BSS_TRNS_RES_STATUS_REJ_LEAVING_ESS 8 ++ ++ ++/* Neighbor Report BSSID Information Field */ ++#define DOT11_NBR_RPRT_BSSID_INFO_REACHABILTY 0x0003 ++#define DOT11_NBR_RPRT_BSSID_INFO_SEC 0x0004 ++#define DOT11_NBR_RPRT_BSSID_INFO_KEY_SCOPE 0x0008 ++#define DOT11_NBR_RPRT_BSSID_INFO_CAP 0x03f0 ++ ++#define DOT11_NBR_RPRT_BSSID_INFO_CAP_SPEC_MGMT 0x0010 ++#define DOT11_NBR_RPRT_BSSID_INFO_CAP_QOS 0x0020 ++#define DOT11_NBR_RPRT_BSSID_INFO_CAP_APSD 0x0040 ++#define DOT11_NBR_RPRT_BSSID_INFO_CAP_RDIO_MSMT 0x0080 ++#define DOT11_NBR_RPRT_BSSID_INFO_CAP_DEL_BA 0x0100 ++#define DOT11_NBR_RPRT_BSSID_INFO_CAP_IMM_BA 0x0200 ++ ++/* Neighbor Report Subelements */ ++#define DOT11_NBR_RPRT_SUBELEM_BSS_CANDDT_PREF_ID 3 ++ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_addba_req { ++ uint8 category; /* category of action frame (3) */ ++ uint8 action; /* action: addba req */ ++ uint8 token; /* identifier */ ++ uint16 addba_param_set; /* parameter set */ ++ uint16 timeout; /* timeout in seconds */ ++ uint16 start_seqnum; /* starting sequence number */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_addba_req dot11_addba_req_t; ++#define DOT11_ADDBA_REQ_LEN 9 /* length of addba req frame */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_addba_resp { ++ uint8 category; /* category of action frame (3) */ ++ uint8 action; /* action: addba resp */ ++ uint8 token; /* identifier */ ++ uint16 status; /* status of add request */ ++ uint16 addba_param_set; /* negotiated parameter set */ ++ uint16 timeout; /* negotiated timeout in seconds */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_addba_resp dot11_addba_resp_t; ++#define DOT11_ADDBA_RESP_LEN 9 /* length of addba resp frame */ ++ ++/* DELBA action parameters */ ++#define DOT11_DELBA_PARAM_INIT_MASK 0x0800 /* initiator mask */ ++#define DOT11_DELBA_PARAM_INIT_SHIFT 11 /* initiator shift */ ++#define DOT11_DELBA_PARAM_TID_MASK 0xf000 /* tid mask */ ++#define DOT11_DELBA_PARAM_TID_SHIFT 12 /* tid shift */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_delba { ++ uint8 category; /* category of action frame (3) */ ++ uint8 action; /* action: addba req */ ++ uint16 delba_param_set; /* paarmeter set */ ++ uint16 reason; /* reason for dellba */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_delba dot11_delba_t; ++#define DOT11_DELBA_LEN 6 /* length of delba frame */ ++ ++/* SA Query action field value */ ++#define SA_QUERY_REQUEST 0 ++#define SA_QUERY_RESPONSE 1 ++ ++/* ************* 802.11r related definitions. ************* */ ++ ++/* Over-the-DS Fast Transition Request frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_ft_req { ++ uint8 category; /* category of action frame (6) */ ++ uint8 action; /* action: ft req */ ++ uint8 sta_addr[ETHER_ADDR_LEN]; ++ uint8 tgt_ap_addr[ETHER_ADDR_LEN]; ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ft_req dot11_ft_req_t; ++#define DOT11_FT_REQ_FIXED_LEN 14 ++ ++/* Over-the-DS Fast Transition Response frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_ft_res { ++ uint8 category; /* category of action frame (6) */ ++ uint8 action; /* action: ft resp */ ++ uint8 sta_addr[ETHER_ADDR_LEN]; ++ uint8 tgt_ap_addr[ETHER_ADDR_LEN]; ++ uint16 status; /* status code */ ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ft_res dot11_ft_res_t; ++#define DOT11_FT_RES_FIXED_LEN 16 ++ ++ ++/* ************* 802.11k related definitions. ************* */ ++ ++/* Radio measurements enabled capability ie */ ++ ++#define DOT11_RRM_CAP_LEN 5 /* length of rrm cap bitmap */ ++BWL_PRE_PACKED_STRUCT struct dot11_rrm_cap_ie { ++ uint8 cap[DOT11_RRM_CAP_LEN]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t; ++ ++/* Bitmap definitions for cap ie */ ++#define DOT11_RRM_CAP_LINK 0 ++#define DOT11_RRM_CAP_NEIGHBOR_REPORT 1 ++#define DOT11_RRM_CAP_PARALLEL 2 ++#define DOT11_RRM_CAP_REPEATED 3 ++#define DOT11_RRM_CAP_BCN_PASSIVE 4 ++#define DOT11_RRM_CAP_BCN_ACTIVE 5 ++#define DOT11_RRM_CAP_BCN_TABLE 6 ++#define DOT11_RRM_CAP_BCN_REP_COND 7 ++#define DOT11_RRM_CAP_AP_CHANREP 16 ++ ++ ++/* Operating Class (formerly "Regulatory Class") definitions */ ++#define DOT11_OP_CLASS_NONE 255 ++ ++ ++/* Radio Measurements action ids */ ++#define DOT11_RM_ACTION_RM_REQ 0 /* Radio measurement request */ ++#define DOT11_RM_ACTION_RM_REP 1 /* Radio measurement report */ ++#define DOT11_RM_ACTION_LM_REQ 2 /* Link measurement request */ ++#define DOT11_RM_ACTION_LM_REP 3 /* Link measurement report */ ++#define DOT11_RM_ACTION_NR_REQ 4 /* Neighbor report request */ ++#define DOT11_RM_ACTION_NR_REP 5 /* Neighbor report response */ ++ ++/* Generic radio measurement action frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_rm_action { ++ uint8 category; /* category of action frame (5) */ ++ uint8 action; /* radio measurement action */ ++ uint8 token; /* dialog token */ ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rm_action dot11_rm_action_t; ++#define DOT11_RM_ACTION_LEN 3 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rmreq { ++ uint8 category; /* category of action frame (5) */ ++ uint8 action; /* radio measurement action */ ++ uint8 token; /* dialog token */ ++ uint16 reps; /* no. of repetitions */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmreq dot11_rmreq_t; ++#define DOT11_RMREQ_LEN 5 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rm_ie { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rm_ie dot11_rm_ie_t; ++#define DOT11_RM_IE_LEN 5 ++ ++/* Definitions for "mode" bits in rm req */ ++#define DOT11_RMREQ_MODE_PARALLEL 1 ++#define DOT11_RMREQ_MODE_ENABLE 2 ++#define DOT11_RMREQ_MODE_REQUEST 4 ++#define DOT11_RMREQ_MODE_REPORT 8 ++#define DOT11_RMREQ_MODE_DURMAND 0x10 /* Duration Mandatory */ ++ ++/* Definitions for "mode" bits in rm rep */ ++#define DOT11_RMREP_MODE_LATE 1 ++#define DOT11_RMREP_MODE_INCAPABLE 2 ++#define DOT11_RMREP_MODE_REFUSED 4 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rmreq_bcn { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint8 reg; ++ uint8 channel; ++ uint16 interval; ++ uint16 duration; ++ uint8 bcn_mode; ++ struct ether_addr bssid; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmreq_bcn dot11_rmreq_bcn_t; ++#define DOT11_RMREQ_BCN_LEN 18 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn { ++ uint8 reg; ++ uint8 channel; ++ uint32 starttime[2]; ++ uint16 duration; ++ uint8 frame_info; ++ uint8 rcpi; ++ uint8 rsni; ++ struct ether_addr bssid; ++ uint8 antenna_id; ++ uint32 parent_tsf; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t; ++#define DOT11_RMREP_BCN_LEN 26 ++ ++/* Beacon request measurement mode */ ++#define DOT11_RMREQ_BCN_PASSIVE 0 ++#define DOT11_RMREQ_BCN_ACTIVE 1 ++#define DOT11_RMREQ_BCN_TABLE 2 ++ ++/* Sub-element IDs for Beacon Request */ ++#define DOT11_RMREQ_BCN_SSID_ID 0 ++#define DOT11_RMREQ_BCN_REPINFO_ID 1 ++#define DOT11_RMREQ_BCN_REPDET_ID 2 ++#define DOT11_RMREQ_BCN_REQUEST_ID 10 ++#define DOT11_RMREQ_BCN_APCHREP_ID 51 ++ ++/* Reporting Detail element definition */ ++#define DOT11_RMREQ_BCN_REPDET_FIXED 0 /* Fixed length fields only */ ++#define DOT11_RMREQ_BCN_REPDET_REQUEST 1 /* + requested information elems */ ++#define DOT11_RMREQ_BCN_REPDET_ALL 2 /* All fields */ ++ ++/* Sub-element IDs for Beacon Report */ ++#define DOT11_RMREP_BCN_FRM_BODY 1 ++ ++/* Neighbor measurement report */ ++BWL_PRE_PACKED_STRUCT struct dot11_rmrep_nbr { ++ struct ether_addr bssid; ++ uint32 bssid_info; ++ uint8 reg; ++ uint8 channel; ++ uint8 phytype; ++ uchar sub_elements[1]; /* Variable size data */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmrep_nbr dot11_rmrep_nbr_t; ++#define DOT11_RMREP_NBR_LEN 13 ++ ++/* MLME Enumerations */ ++#define DOT11_BSSTYPE_INFRASTRUCTURE 0 /* d11 infrastructure */ ++#define DOT11_BSSTYPE_INDEPENDENT 1 /* d11 independent */ ++#define DOT11_BSSTYPE_ANY 2 /* d11 any BSS type */ ++#define DOT11_SCANTYPE_ACTIVE 0 /* d11 scan active */ ++#define DOT11_SCANTYPE_PASSIVE 1 /* d11 scan passive */ ++ ++/* Link Measurement */ ++BWL_PRE_PACKED_STRUCT struct dot11_lmreq { ++ uint8 category; /* category of action frame (5) */ ++ uint8 action; /* radio measurement action */ ++ uint8 token; /* dialog token */ ++ uint8 txpwr; /* Transmit Power Used */ ++ uint8 maxtxpwr; /* Max Transmit Power */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_lmreq dot11_lmreq_t; ++#define DOT11_LMREQ_LEN 5 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_lmrep { ++ uint8 category; /* category of action frame (5) */ ++ uint8 action; /* radio measurement action */ ++ uint8 token; /* dialog token */ ++ dot11_tpc_rep_t tpc; /* TPC element */ ++ uint8 rxant; /* Receive Antenna ID */ ++ uint8 txant; /* Transmit Antenna ID */ ++ uint8 rcpi; /* RCPI */ ++ uint8 rsni; /* RSNI */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_lmrep dot11_lmrep_t; ++#define DOT11_LMREP_LEN 11 ++ ++/* 802.11 BRCM "Compromise" Pre N constants */ ++#define PREN_PREAMBLE 24 /* green field preamble time */ ++#define PREN_MM_EXT 12 /* extra mixed mode preamble time */ ++#define PREN_PREAMBLE_EXT 4 /* extra preamble (multiply by unique_streams-1) */ ++ ++/* 802.11N PHY constants */ ++#define RIFS_11N_TIME 2 /* NPHY RIFS time */ ++ ++/* 802.11 HT PLCP format 802.11n-2009, sec 20.3.9.4.3 ++ * HT-SIG is composed of two 24 bit parts, HT-SIG1 and HT-SIG2 ++ */ ++/* HT-SIG1 */ ++#define HT_SIG1_MCS_MASK 0x00007F ++#define HT_SIG1_CBW 0x000080 ++#define HT_SIG1_HT_LENGTH 0xFFFF00 ++ ++/* HT-SIG2 */ ++#define HT_SIG2_SMOOTHING 0x000001 ++#define HT_SIG2_NOT_SOUNDING 0x000002 ++#define HT_SIG2_RESERVED 0x000004 ++#define HT_SIG2_AGGREGATION 0x000008 ++#define HT_SIG2_STBC_MASK 0x000030 ++#define HT_SIG2_STBC_SHIFT 4 ++#define HT_SIG2_FEC_CODING 0x000040 ++#define HT_SIG2_SHORT_GI 0x000080 ++#define HT_SIG2_ESS_MASK 0x000300 ++#define HT_SIG2_ESS_SHIFT 8 ++#define HT_SIG2_CRC 0x03FC00 ++#define HT_SIG2_TAIL 0x1C0000 ++ ++/* 802.11 A PHY constants */ ++#define APHY_SLOT_TIME 9 /* APHY slot time */ ++#define APHY_SIFS_TIME 16 /* APHY SIFS time */ ++#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME)) /* APHY DIFS time */ ++#define APHY_PREAMBLE_TIME 16 /* APHY preamble time */ ++#define APHY_SIGNAL_TIME 4 /* APHY signal time */ ++#define APHY_SYMBOL_TIME 4 /* APHY symbol time */ ++#define APHY_SERVICE_NBITS 16 /* APHY service nbits */ ++#define APHY_TAIL_NBITS 6 /* APHY tail nbits */ ++#define APHY_CWMIN 15 /* APHY cwmin */ ++ ++/* 802.11 B PHY constants */ ++#define BPHY_SLOT_TIME 20 /* BPHY slot time */ ++#define BPHY_SIFS_TIME 10 /* BPHY SIFS time */ ++#define BPHY_DIFS_TIME 50 /* BPHY DIFS time */ ++#define BPHY_PLCP_TIME 192 /* BPHY PLCP time */ ++#define BPHY_PLCP_SHORT_TIME 96 /* BPHY PLCP short time */ ++#define BPHY_CWMIN 31 /* BPHY cwmin */ ++ ++/* 802.11 G constants */ ++#define DOT11_OFDM_SIGNAL_EXTENSION 6 /* d11 OFDM signal extension */ ++ ++#define PHY_CWMAX 1023 /* PHY cwmax */ ++ ++#define DOT11_MAXNUMFRAGS 16 /* max # fragments per MSDU */ ++ ++/* 802.11 AC (VHT) constants */ ++ ++typedef int vht_group_id_t; ++ ++/* for VHT-A1 */ ++/* SIG-A1 reserved bits */ ++#define VHT_SIGA1_CONST_MASK 0x800004 ++ ++#define VHT_SIGA1_20MHZ_VAL 0x000000 ++#define VHT_SIGA1_40MHZ_VAL 0x000001 ++#define VHT_SIGA1_80MHZ_VAL 0x000002 ++#define VHT_SIGA1_160MHZ_VAL 0x000003 ++ ++#define VHT_SIGA1_STBC 0x000008 ++ ++#define VHT_SIGA1_GID_MAX_GID 0x3f ++#define VHT_SIGA1_GID_SHIFT 4 ++#define VHT_SIGA1_GID_TO_AP 0x00 ++#define VHT_SIGA1_GID_NOT_TO_AP 0x3f ++ ++#define VHT_SIGA1_NSTS_SHIFT 10 ++#define VHT_SIGA1_NSTS_SHIFT_MASK_USER0 0x001C00 ++ ++#define VHT_SIGA1_PARTIAL_AID_SHIFT 13 ++ ++/* for VHT-A2 */ ++#define VHT_SIGA2_GI_NONE 0x000000 ++#define VHT_SIGA2_GI_SHORT 0x000001 ++#define VHT_SIGA2_GI_W_MOD10 0x000002 ++#define VHT_SIGA2_CODING_LDPC 0x000004 ++#define VHT_SIGA2_BEAMFORM_ENABLE 0x000100 ++#define VHT_SIGA2_MCS_SHIFT 4 ++ ++#define VHT_SIGA2_B9_RESERVED 0x000200 ++#define VHT_SIGA2_TAIL_MASK 0xfc0000 ++#define VHT_SIGA2_TAIL_VALUE 0x000000 ++ ++#define VHT_SIGA2_SVC_BITS 16 ++#define VHT_SIGA2_TAIL_BITS 6 ++ ++ ++/* dot11Counters Table - 802.11 spec., Annex D */ ++typedef struct d11cnt { ++ uint32 txfrag; /* dot11TransmittedFragmentCount */ ++ uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ ++ uint32 txfail; /* dot11FailedCount */ ++ uint32 txretry; /* dot11RetryCount */ ++ uint32 txretrie; /* dot11MultipleRetryCount */ ++ uint32 rxdup; /* dot11FrameduplicateCount */ ++ uint32 txrts; /* dot11RTSSuccessCount */ ++ uint32 txnocts; /* dot11RTSFailureCount */ ++ uint32 txnoack; /* dot11ACKFailureCount */ ++ uint32 rxfrag; /* dot11ReceivedFragmentCount */ ++ uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ ++ uint32 rxcrc; /* dot11FCSErrorCount */ ++ uint32 txfrmsnt; /* dot11TransmittedFrameCount */ ++ uint32 rxundec; /* dot11WEPUndecryptableCount */ ++} d11cnt_t; ++ ++/* OUI for BRCM proprietary IE */ ++#define BRCM_PROP_OUI "\x00\x90\x4C" /* Broadcom proprietary OUI */ ++ ++ ++/* BRCM OUI: Used in the proprietary(221) IE in all broadcom devices */ ++#define BRCM_OUI "\x00\x10\x18" /* Broadcom OUI */ ++ ++/* BRCM info element */ ++BWL_PRE_PACKED_STRUCT struct brcm_ie { ++ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ ++ uint8 len; /* IE length */ ++ uint8 oui[3]; /* Proprietary OUI, BRCM_OUI */ ++ uint8 ver; /* type/ver of this IE */ ++ uint8 assoc; /* # of assoc STAs */ ++ uint8 flags; /* misc flags */ ++ uint8 flags1; /* misc flags */ ++ uint16 amsdu_mtu_pref; /* preferred A-MSDU MTU */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct brcm_ie brcm_ie_t; ++#define BRCM_IE_LEN 11 /* BRCM IE length */ ++#define BRCM_IE_VER 2 /* BRCM IE version */ ++#define BRCM_IE_LEGACY_AES_VER 1 /* BRCM IE legacy AES version */ ++ ++/* brcm_ie flags */ ++#define BRF_LZWDS 0x4 /* lazy wds enabled */ ++#define BRF_BLOCKACK 0x8 /* BlockACK capable */ ++ ++/* brcm_ie flags1 */ ++#define BRF1_AMSDU 0x1 /* A-MSDU capable */ ++#define BRF1_WMEPS 0x4 /* AP is capable of handling WME + PS w/o APSD */ ++#define BRF1_PSOFIX 0x8 /* AP has fixed PS mode out-of-order packets */ ++#define BRF1_RX_LARGE_AGG 0x10 /* device can rx large aggregates */ ++#define BRF1_RFAWARE_DCS 0x20 /* RFAWARE dynamic channel selection (DCS) */ ++#define BRF1_SOFTAP 0x40 /* Configure as Broadcom SOFTAP */ ++ ++/* Vendor IE structure */ ++BWL_PRE_PACKED_STRUCT struct vndr_ie { ++ uchar id; ++ uchar len; ++ uchar oui [3]; ++ uchar data [1]; /* Variable size data */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct vndr_ie vndr_ie_t; ++ ++#define VNDR_IE_HDR_LEN 2 /* id + len field */ ++#define VNDR_IE_MIN_LEN 3 /* size of the oui field */ ++#define VNDR_IE_FIXED_LEN (VNDR_IE_HDR_LEN + VNDR_IE_MIN_LEN) ++#define VNDR_IE_MAX_LEN 256 /* verdor IE max length */ ++ ++/* ************* HT definitions. ************* */ ++#define MCSSET_LEN 16 /* 16-bits per 8-bit set to give 128-bits bitmap of MCS Index */ ++#define MAX_MCS_NUM (128) /* max mcs number = 128 */ ++ ++BWL_PRE_PACKED_STRUCT struct ht_cap_ie { ++ uint16 cap; ++ uint8 params; ++ uint8 supp_mcs[MCSSET_LEN]; ++ uint16 ext_htcap; ++ uint32 txbf_cap; ++ uint8 as_cap; ++} BWL_POST_PACKED_STRUCT; ++typedef struct ht_cap_ie ht_cap_ie_t; ++ ++/* CAP IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ ++/* the capability IE is primarily used to convey this nodes abilities */ ++BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie { ++ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ ++ uint8 len; /* IE length */ ++ uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ ++ uint8 type; /* type inidicates what follows */ ++ ht_cap_ie_t cap_ie; ++} BWL_POST_PACKED_STRUCT; ++typedef struct ht_prop_cap_ie ht_prop_cap_ie_t; ++ ++#define HT_PROP_IE_OVERHEAD 4 /* overhead bytes for prop oui ie */ ++#define HT_CAP_IE_LEN 26 /* HT capability len (based on .11n d2.0) */ ++#define HT_CAP_IE_TYPE 51 ++ ++#define HT_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */ ++#define HT_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */ ++#define HT_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */ ++#define HT_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */ ++#define HT_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */ ++#define HT_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */ ++#define HT_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */ ++#define HT_CAP_GF 0x0010 /* Greenfield preamble support */ ++#define HT_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */ ++#define HT_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */ ++#define HT_CAP_TX_STBC 0x0080 /* Tx STBC support */ ++#define HT_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */ ++#define HT_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */ ++#define HT_CAP_DELAYED_BA 0x0400 /* delayed BA support */ ++#define HT_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */ ++ ++#define HT_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */ ++#define HT_CAP_PSMP 0x2000 /* Power Save Multi Poll support */ ++#define HT_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */ ++#define HT_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */ ++ ++#define HT_CAP_RX_STBC_NO 0x0 /* no rx STBC support */ ++#define HT_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */ ++#define HT_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ ++#define HT_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ ++ ++#define VHT_MAX_MPDU 11454 /* max mpdu size for now (bytes) */ ++#define VHT_MPDU_MSDU_DELTA 56 /* Difference in spec - vht mpdu, amsdu len */ ++/* Max AMSDU len - per spec */ ++#define VHT_MAX_AMSDU (VHT_MAX_MPDU - VHT_MPDU_MSDU_DELTA) ++ ++#define HT_MAX_AMSDU 7935 /* max amsdu size (bytes) per the HT spec */ ++#define HT_MIN_AMSDU 3835 /* min amsdu size (bytes) per the HT spec */ ++ ++#define HT_PARAMS_RX_FACTOR_MASK 0x03 /* ampdu rcv factor mask */ ++#define HT_PARAMS_DENSITY_MASK 0x1C /* ampdu density mask */ ++#define HT_PARAMS_DENSITY_SHIFT 2 /* ampdu density shift */ ++ ++/* HT/AMPDU specific define */ ++#define AMPDU_MAX_MPDU_DENSITY 7 /* max mpdu density; in 1/4 usec units */ ++#define AMPDU_DENSITY_NONE 0 /* No density requirement */ ++#define AMPDU_DENSITY_1over4_US 1 /* 1/4 us density */ ++#define AMPDU_DENSITY_1over2_US 2 /* 1/2 us density */ ++#define AMPDU_DENSITY_1_US 3 /* 1 us density */ ++#define AMPDU_DENSITY_2_US 4 /* 2 us density */ ++#define AMPDU_DENSITY_4_US 5 /* 4 us density */ ++#define AMPDU_DENSITY_8_US 6 /* 8 us density */ ++#define AMPDU_DENSITY_16_US 7 /* 16 us density */ ++#define AMPDU_RX_FACTOR_8K 0 /* max rcv ampdu len (8kb) */ ++#define AMPDU_RX_FACTOR_16K 1 /* max rcv ampdu len (16kb) */ ++#define AMPDU_RX_FACTOR_32K 2 /* max rcv ampdu len (32kb) */ ++#define AMPDU_RX_FACTOR_64K 3 /* max rcv ampdu len (64kb) */ ++#define AMPDU_RX_FACTOR_BASE 8*1024 /* ampdu factor base for rx len */ ++ ++#define AMPDU_DELIMITER_LEN 4 /* length of ampdu delimiter */ ++#define AMPDU_DELIMITER_LEN_MAX 63 /* max length of ampdu delimiter(enforced in HW) */ ++ ++#define HT_CAP_EXT_PCO 0x0001 ++#define HT_CAP_EXT_PCO_TTIME_MASK 0x0006 ++#define HT_CAP_EXT_PCO_TTIME_SHIFT 1 ++#define HT_CAP_EXT_MCS_FEEDBACK_MASK 0x0300 ++#define HT_CAP_EXT_MCS_FEEDBACK_SHIFT 8 ++#define HT_CAP_EXT_HTC 0x0400 ++#define HT_CAP_EXT_RD_RESP 0x0800 ++ ++BWL_PRE_PACKED_STRUCT struct ht_add_ie { ++ uint8 ctl_ch; /* control channel number */ ++ uint8 byte1; /* ext ch,rec. ch. width, RIFS support */ ++ uint16 opmode; /* operation mode */ ++ uint16 misc_bits; /* misc bits */ ++ uint8 basic_mcs[MCSSET_LEN]; /* required MCS set */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct ht_add_ie ht_add_ie_t; ++ ++/* ADD IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ ++/* the additional IE is primarily used to convey the current BSS configuration */ ++BWL_PRE_PACKED_STRUCT struct ht_prop_add_ie { ++ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ ++ uint8 len; /* IE length */ ++ uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ ++ uint8 type; /* indicates what follows */ ++ ht_add_ie_t add_ie; ++} BWL_POST_PACKED_STRUCT; ++typedef struct ht_prop_add_ie ht_prop_add_ie_t; ++ ++#define HT_ADD_IE_LEN 22 ++#define HT_ADD_IE_TYPE 52 ++ ++/* byte1 defn's */ ++#define HT_BW_ANY 0x04 /* set, STA can use 20 or 40MHz */ ++#define HT_RIFS_PERMITTED 0x08 /* RIFS allowed */ ++ ++/* opmode defn's */ ++#define HT_OPMODE_MASK 0x0003 /* protection mode mask */ ++#define HT_OPMODE_SHIFT 0 /* protection mode shift */ ++#define HT_OPMODE_PURE 0x0000 /* protection mode PURE */ ++#define HT_OPMODE_OPTIONAL 0x0001 /* protection mode optional */ ++#define HT_OPMODE_HT20IN40 0x0002 /* protection mode 20MHz HT in 40MHz BSS */ ++#define HT_OPMODE_MIXED 0x0003 /* protection mode Mixed Mode */ ++#define HT_OPMODE_NONGF 0x0004 /* protection mode non-GF */ ++#define DOT11N_TXBURST 0x0008 /* Tx burst limit */ ++#define DOT11N_OBSS_NONHT 0x0010 /* OBSS Non-HT STA present */ ++ ++/* misc_bites defn's */ ++#define HT_BASIC_STBC_MCS 0x007f /* basic STBC MCS */ ++#define HT_DUAL_STBC_PROT 0x0080 /* Dual STBC Protection */ ++#define HT_SECOND_BCN 0x0100 /* Secondary beacon support */ ++#define HT_LSIG_TXOP 0x0200 /* L-SIG TXOP Protection full support */ ++#define HT_PCO_ACTIVE 0x0400 /* PCO active */ ++#define HT_PCO_PHASE 0x0800 /* PCO phase */ ++#define HT_DUALCTS_PROTECTION 0x0080 /* DUAL CTS protection needed */ ++ ++/* Tx Burst Limits */ ++#define DOT11N_2G_TXBURST_LIMIT 6160 /* 2G band Tx burst limit per 802.11n Draft 1.10 (usec) */ ++#define DOT11N_5G_TXBURST_LIMIT 3080 /* 5G band Tx burst limit per 802.11n Draft 1.10 (usec) */ ++ ++/* Macros for opmode */ ++#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ ++ >> HT_OPMODE_SHIFT) ++#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ ++ == HT_OPMODE_MIXED) /* mixed mode present */ ++#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ ++ == HT_OPMODE_HT20IN40) /* 20MHz HT present */ ++#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ ++ == HT_OPMODE_OPTIONAL) /* Optional protection present */ ++#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \ ++ HT_MIXEDMODE_PRESENT((add_ie))) /* use protection */ ++#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \ ++ == HT_OPMODE_NONGF) /* non-GF present */ ++#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \ ++ == DOT11N_TXBURST) /* Tx Burst present */ ++#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \ ++ == DOT11N_OBSS_NONHT) /* OBSS Non-HT present */ ++ ++BWL_PRE_PACKED_STRUCT struct obss_params { ++ uint16 passive_dwell; ++ uint16 active_dwell; ++ uint16 bss_widthscan_interval; ++ uint16 passive_total; ++ uint16 active_total; ++ uint16 chanwidth_transition_dly; ++ uint16 activity_threshold; ++} BWL_POST_PACKED_STRUCT; ++typedef struct obss_params obss_params_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_obss_ie { ++ uint8 id; ++ uint8 len; ++ obss_params_t obss_params; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_obss_ie dot11_obss_ie_t; ++#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t) /* HT OBSS len (based on 802.11n d3.0) */ ++ ++/* HT control field */ ++#define HT_CTRL_LA_TRQ 0x00000002 /* sounding request */ ++#define HT_CTRL_LA_MAI 0x0000003C /* MCS request or antenna selection indication */ ++#define HT_CTRL_LA_MAI_SHIFT 2 ++#define HT_CTRL_LA_MAI_MRQ 0x00000004 /* MCS request */ ++#define HT_CTRL_LA_MAI_MSI 0x00000038 /* MCS request sequence identifier */ ++#define HT_CTRL_LA_MFSI 0x000001C0 /* MFB sequence identifier */ ++#define HT_CTRL_LA_MFSI_SHIFT 6 ++#define HT_CTRL_LA_MFB_ASELC 0x0000FE00 /* MCS feedback, antenna selection command/data */ ++#define HT_CTRL_LA_MFB_ASELC_SH 9 ++#define HT_CTRL_LA_ASELC_CMD 0x00000C00 /* ASEL command */ ++#define HT_CTRL_LA_ASELC_DATA 0x0000F000 /* ASEL data */ ++#define HT_CTRL_CAL_POS 0x00030000 /* Calibration position */ ++#define HT_CTRL_CAL_SEQ 0x000C0000 /* Calibration sequence */ ++#define HT_CTRL_CSI_STEERING 0x00C00000 /* CSI/Steering */ ++#define HT_CTRL_CSI_STEER_SHIFT 22 ++#define HT_CTRL_CSI_STEER_NFB 0 /* no fedback required */ ++#define HT_CTRL_CSI_STEER_CSI 1 /* CSI, H matrix */ ++#define HT_CTRL_CSI_STEER_NCOM 2 /* non-compressed beamforming */ ++#define HT_CTRL_CSI_STEER_COM 3 /* compressed beamforming */ ++#define HT_CTRL_NDP_ANNOUNCE 0x01000000 /* NDP announcement */ ++#define HT_CTRL_AC_CONSTRAINT 0x40000000 /* AC Constraint */ ++#define HT_CTRL_RDG_MOREPPDU 0x80000000 /* RDG/More PPDU */ ++ ++#define HT_OPMODE_OPTIONAL 0x0001 /* protection mode optional */ ++#define HT_OPMODE_HT20IN40 0x0002 /* protection mode 20MHz HT in 40MHz BSS */ ++#define HT_OPMODE_MIXED 0x0003 /* protection mode Mixed Mode */ ++#define HT_OPMODE_NONGF 0x0004 /* protection mode non-GF */ ++#define DOT11N_TXBURST 0x0008 /* Tx burst limit */ ++#define DOT11N_OBSS_NONHT 0x0010 /* OBSS Non-HT STA present */ ++ ++/* ************* VHT definitions. ************* */ ++ ++BWL_PRE_PACKED_STRUCT struct vht_cap_ie { ++ uint32 vht_cap_info; ++ /* supported MCS set - 64 bit field */ ++ uint16 rx_mcs_map; ++ uint16 rx_max_rate; ++ uint16 tx_mcs_map; ++ uint16 tx_max_rate; ++} BWL_POST_PACKED_STRUCT; ++typedef struct vht_cap_ie vht_cap_ie_t; ++/* 4B cap_info + 8B supp_mcs */ ++#define VHT_CAP_IE_LEN 12 ++/* 32bit - cap info */ ++#define VHT_CAP_INFO_MAX_MPDU_LEN_MASK 0x00000003 ++#define VHT_CAP_INFO_SUPP_CHAN_WIDTH_MASK 0x0000000c ++#define VHT_CAP_INFO_LDPC 0x00000010 ++#define VHT_CAP_INFO_SGI_80MHZ 0x00000020 ++ ++#define VHT_CAP_INFO_SGI_160MHZ 0x00000040 ++#define VHT_CAP_INFO_TX_STBC 0x00000080 ++ ++#define VHT_CAP_INFO_RX_STBC_MASK 0x00000700 ++#define VHT_CAP_INFO_RX_STBC_SHIFT 8 ++#define VHT_CAP_INFO_SU_BEAMFMR 0x00000800 ++#define VHT_CAP_INFO_SU_BEAMFMEE 0x00001000 ++#define VHT_CAP_INFO_NUM_BMFMR_ANT_MASK 0x0000e000 ++#define VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT 13 ++ ++#define VHT_CAP_INFO_NUM_SOUNDING_DIM_MASK 0x00070000 ++#define VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT 16 ++#define VHT_CAP_INFO_MU_BEAMFMR 0x00080000 ++#define VHT_CAP_INFO_MU_BEAMFMEE 0x00100000 ++#define VHT_CAP_INFO_TXOPPS 0x00200000 ++#define VHT_CAP_INFO_HTCVHT 0x00400000 ++#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_MASK 0x03800000 ++#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT 23 ++ ++#define VHT_CAP_INFO_LINK_ADAPT_CAP_MASK 0x0c000000 ++#define VHT_CAP_INFO_LINK_ADAPT_CAP_SHIFT 26 ++ ++/* 64-bit Supp MCS. */ ++#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_MASK 0x1fff ++#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_SHIFT 0 ++ ++#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_MASK 0x1fff ++#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_SHIFT 0 ++ ++#define VHT_CAP_MCS_MAP_0_7 0 ++#define VHT_CAP_MCS_MAP_0_8 1 ++#define VHT_CAP_MCS_MAP_0_9 2 ++#define VHT_CAP_MCS_MAP_NONE 3 ++ ++#define VHT_CAP_MCS_MAP_NSS_MAX 8 ++ ++/* VHT Capabilities Supported Channel Width */ ++typedef enum vht_cap_chan_width { ++ VHT_CAP_CHAN_WIDTH_20_40 = 0x00, ++ VHT_CAP_CHAN_WIDTH_80 = 0x04, ++ VHT_CAP_CHAN_WIDTH_160 = 0x08 ++} vht_cap_chan_width_t; ++ ++/* VHT Capabilities Supported max MPDU LEN */ ++typedef enum vht_cap_max_mpdu_len { ++ VHT_CAP_MPDU_MAX_4K = 0x00, ++ VHT_CAP_MPDU_MAX_8K = 0x01, ++ VHT_CAP_MPDU_MAX_11K = 0x02 ++} vht_cap_max_mpdu_len_t; ++ ++/* VHT Operation Element */ ++BWL_PRE_PACKED_STRUCT struct vht_op_ie { ++ uint8 chan_width; ++ uint8 chan1; ++ uint8 chan2; ++ uint16 supp_mcs; /* same def as above in vht cap */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct vht_op_ie vht_op_ie_t; ++/* 3B VHT Op info + 2B Basic MCS */ ++#define VHT_OP_IE_LEN 5 ++ ++typedef enum vht_op_chan_width { ++ VHT_OP_CHAN_WIDTH_20_40 = 0, ++ VHT_OP_CHAN_WIDTH_80 = 1, ++ VHT_OP_CHAN_WIDTH_160 = 2, ++ VHT_OP_CHAN_WIDTH_80_80 = 3 ++} vht_op_chan_width_t; ++ ++/* Def for rx & tx basic mcs maps - ea ss num has 2 bits of info */ ++#define VHT_MCS_MAP_GET_SS_IDX(nss) (((nss)-1)*2) ++#define VHT_MCS_MAP_GET_MCS_PER_SS(nss, mcsMap) \ ++ (((mcsMap) >> VHT_MCS_MAP_GET_SS_IDX(nss)) & 0x3) ++#define VHT_MCS_MAP_SET_MCS_PER_SS(nss, numMcs, mcsMap) \ ++ ((mcsMap) |= (((numMcs) & 0x3) << VHT_MCS_MAP_GET_SS_IDX(nss))) ++ ++/* ************* WPA definitions. ************* */ ++#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ ++#define WPA_OUI_LEN 3 /* WPA OUI length */ ++#define WPA_OUI_TYPE 1 ++#define WPA_VERSION 1 /* WPA version */ ++#define WPA2_OUI "\x00\x0F\xAC" /* WPA2 OUI */ ++#define WPA2_OUI_LEN 3 /* WPA2 OUI length */ ++#define WPA2_VERSION 1 /* WPA2 version */ ++#define WPA2_VERSION_LEN 2 /* WAP2 version length */ ++ ++/* ************* WPS definitions. ************* */ ++#define WPS_OUI "\x00\x50\xF2" /* WPS OUI */ ++#define WPS_OUI_LEN 3 /* WPS OUI length */ ++#define WPS_OUI_TYPE 4 ++ ++/* ************* WFA definitions. ************* */ ++ ++#ifdef P2P_IE_OVRD ++#define WFA_OUI MAC_OUI ++#else ++#define WFA_OUI "\x50\x6F\x9A" /* WFA OUI */ ++#endif /* P2P_IE_OVRD */ ++#define WFA_OUI_LEN 3 /* WFA OUI length */ ++#ifdef P2P_IE_OVRD ++#define WFA_OUI_TYPE_P2P MAC_OUI_TYPE_P2P ++#else ++#define WFA_OUI_TYPE_P2P 9 ++#endif ++ ++#define WFA_OUI_TYPE_TPC 8 ++#ifdef WLTDLS ++#define WFA_OUI_TYPE_WFD 10 ++#endif /* WTDLS */ ++ ++/* RSN authenticated key managment suite */ ++#define RSN_AKM_NONE 0 /* None (IBSS) */ ++#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */ ++#define RSN_AKM_PSK 2 /* Pre-shared Key */ ++#define RSN_AKM_FBT_1X 3 /* Fast Bss transition using 802.1X */ ++#define RSN_AKM_FBT_PSK 4 /* Fast Bss transition using Pre-shared Key */ ++#define RSN_AKM_MFP_1X 5 /* SHA256 key derivation, using 802.1X */ ++#define RSN_AKM_MFP_PSK 6 /* SHA256 key derivation, using Pre-shared Key */ ++#define RSN_AKM_TPK 7 /* TPK(TDLS Peer Key) handshake */ ++ ++/* Key related defines */ ++#define DOT11_MAX_DEFAULT_KEYS 4 /* number of default keys */ ++#define DOT11_MAX_KEY_SIZE 32 /* max size of any key */ ++#define DOT11_MAX_IV_SIZE 16 /* max size of any IV */ ++#define DOT11_EXT_IV_FLAG (1<<5) /* flag to indicate IV is > 4 bytes */ ++#define DOT11_WPA_KEY_RSC_LEN 8 /* WPA RSC key len */ ++ ++#define WEP1_KEY_SIZE 5 /* max size of any WEP key */ ++#define WEP1_KEY_HEX_SIZE 10 /* size of WEP key in hex. */ ++#define WEP128_KEY_SIZE 13 /* max size of any WEP key */ ++#define WEP128_KEY_HEX_SIZE 26 /* size of WEP key in hex. */ ++#define TKIP_MIC_SIZE 8 /* size of TKIP MIC */ ++#define TKIP_EOM_SIZE 7 /* max size of TKIP EOM */ ++#define TKIP_EOM_FLAG 0x5a /* TKIP EOM flag byte */ ++#define TKIP_KEY_SIZE 32 /* size of any TKIP key */ ++#define TKIP_MIC_AUTH_TX 16 /* offset to Authenticator MIC TX key */ ++#define TKIP_MIC_AUTH_RX 24 /* offset to Authenticator MIC RX key */ ++#define TKIP_MIC_SUP_RX TKIP_MIC_AUTH_TX /* offset to Supplicant MIC RX key */ ++#define TKIP_MIC_SUP_TX TKIP_MIC_AUTH_RX /* offset to Supplicant MIC TX key */ ++#define AES_KEY_SIZE 16 /* size of AES key */ ++#define AES_MIC_SIZE 8 /* size of AES MIC */ ++#define BIP_KEY_SIZE 16 /* size of BIP key */ ++ ++/* WCN */ ++#define WCN_OUI "\x00\x50\xf2" /* WCN OUI */ ++#define WCN_TYPE 4 /* WCN type */ ++#ifdef BCMWAPI_WPI ++#define SMS4_KEY_LEN 16 ++#define SMS4_WPI_CBC_MAC_LEN 16 ++#endif ++ ++ ++/* 802.11r protocol definitions */ ++ ++/* Mobility Domain IE */ ++BWL_PRE_PACKED_STRUCT struct dot11_mdid_ie { ++ uint8 id; ++ uint8 len; ++ uint16 mdid; /* Mobility Domain Id */ ++ uint8 cap; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_mdid_ie dot11_mdid_ie_t; ++ ++#define FBT_MDID_CAP_OVERDS 0x01 /* Fast Bss transition over the DS support */ ++#define FBT_MDID_CAP_RRP 0x02 /* Resource request protocol support */ ++ ++/* Fast Bss Transition IE */ ++BWL_PRE_PACKED_STRUCT struct dot11_ft_ie { ++ uint8 id; ++ uint8 len; ++ uint16 mic_control; /* Mic Control */ ++ uint8 mic[16]; ++ uint8 anonce[32]; ++ uint8 snonce[32]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ft_ie dot11_ft_ie_t; ++ ++#define TIE_TYPE_RESERVED 0 ++#define TIE_TYPE_REASSOC_DEADLINE 1 ++#define TIE_TYPE_KEY_LIEFTIME 2 ++#define TIE_TYPE_ASSOC_COMEBACK 3 ++BWL_PRE_PACKED_STRUCT struct dot11_timeout_ie { ++ uint8 id; ++ uint8 len; ++ uint8 type; /* timeout interval type */ ++ uint32 value; /* timeout interval value */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_timeout_ie dot11_timeout_ie_t; ++ ++ ++/* GTK ie */ ++BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie { ++ uint8 id; ++ uint8 len; ++ uint16 key_info; ++ uint8 key_len; ++ uint8 rsc[8]; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_gtk_ie dot11_gtk_ie_t; ++ ++#define BSSID_INVALID "\x00\x00\x00\x00\x00\x00" ++#define BSSID_BROADCAST "\xFF\xFF\xFF\xFF\xFF\xFF" ++ ++ ++/* ************* WMM Parameter definitions. ************* */ ++#define WMM_OUI "\x00\x50\xF2" /* WNN OUI */ ++#define WMM_OUI_LEN 3 /* WMM OUI length */ ++#define WMM_OUI_TYPE 2 /* WMM OUT type */ ++#define WMM_VERSION 1 ++#define WMM_VERSION_LEN 1 ++ ++/* WMM OUI subtype */ ++#define WMM_OUI_SUBTYPE_PARAMETER 1 ++#define WMM_PARAMETER_IE_LEN 24 ++ ++/* Link Identifier Element */ ++BWL_PRE_PACKED_STRUCT struct link_id_ie { ++ uint8 id; ++ uint8 len; ++ struct ether_addr bssid; ++ struct ether_addr tdls_init_mac; ++ struct ether_addr tdls_resp_mac; ++} BWL_POST_PACKED_STRUCT; ++typedef struct link_id_ie link_id_ie_t; ++#define TDLS_LINK_ID_IE_LEN 18 ++ ++/* Link Wakeup Schedule Element */ ++BWL_PRE_PACKED_STRUCT struct wakeup_sch_ie { ++ uint8 id; ++ uint8 len; ++ uint32 offset; /* in ms between TSF0 and start of 1st Awake Window */ ++ uint32 interval; /* in ms bwtween the start of 2 Awake Windows */ ++ uint32 awake_win_slots; /* in backof slots, duration of Awake Window */ ++ uint32 max_wake_win; /* in ms, max duration of Awake Window */ ++ uint16 idle_cnt; /* number of consecutive Awake Windows */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wakeup_sch_ie wakeup_sch_ie_t; ++#define TDLS_WAKEUP_SCH_IE_LEN 18 ++ ++/* Channel Switch Timing Element */ ++BWL_PRE_PACKED_STRUCT struct channel_switch_timing_ie { ++ uint8 id; ++ uint8 len; ++ uint16 switch_time; /* in ms, time to switch channels */ ++ uint16 switch_timeout; /* in ms */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct channel_switch_timing_ie channel_switch_timing_ie_t; ++#define TDLS_CHANNEL_SWITCH_TIMING_IE_LEN 4 ++ ++/* PTI Control Element */ ++BWL_PRE_PACKED_STRUCT struct pti_control_ie { ++ uint8 id; ++ uint8 len; ++ uint8 tid; ++ uint16 seq_control; ++} BWL_POST_PACKED_STRUCT; ++typedef struct pti_control_ie pti_control_ie_t; ++#define TDLS_PTI_CONTROL_IE_LEN 3 ++ ++/* PU Buffer Status Element */ ++BWL_PRE_PACKED_STRUCT struct pu_buffer_status_ie { ++ uint8 id; ++ uint8 len; ++ uint8 status; ++} BWL_POST_PACKED_STRUCT; ++typedef struct pu_buffer_status_ie pu_buffer_status_ie_t; ++#define TDLS_PU_BUFFER_STATUS_IE_LEN 1 ++#define TDLS_PU_BUFFER_STATUS_AC_BK 1 ++#define TDLS_PU_BUFFER_STATUS_AC_BE 2 ++#define TDLS_PU_BUFFER_STATUS_AC_VI 4 ++#define TDLS_PU_BUFFER_STATUS_AC_VO 8 ++ ++#ifdef BCMWAPI_WAI ++#define WAPI_IE_MIN_LEN 20 /* WAPI IE min length */ ++#define WAPI_VERSION 1 /* WAPI version */ ++#define WAPI_VERSION_LEN 2 /* WAPI version length */ ++#define WAPI_OUI "\x00\x14\x72" /* WAPI OUI */ ++#define WAPI_OUI_LEN DOT11_OUI_LEN /* WAPI OUI length */ ++#endif /* BCMWAPI_WAI */ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _802_11_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/802.11_bta.h b/drivers/net/wireless/ap6211/include/proto/802.11_bta.h +new file mode 100755 +index 0000000..3ee5a74 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/802.11_bta.h +@@ -0,0 +1,45 @@ ++/* ++ * BT-AMP (BlueTooth Alternate Mac and Phy) 802.11 PAL (Protocol Adaptation Layer) ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: 802.11_bta.h 294267 2011-11-04 23:41:52Z $ ++*/ ++ ++#ifndef _802_11_BTA_H_ ++#define _802_11_BTA_H_ ++ ++#define BT_SIG_SNAP_MPROT "\xAA\xAA\x03\x00\x19\x58" ++ ++/* BT-AMP 802.11 PAL Protocols */ ++#define BTA_PROT_L2CAP 1 ++#define BTA_PROT_ACTIVITY_REPORT 2 ++#define BTA_PROT_SECURITY 3 ++#define BTA_PROT_LINK_SUPERVISION_REQUEST 4 ++#define BTA_PROT_LINK_SUPERVISION_REPLY 5 ++ ++/* BT-AMP 802.11 PAL AMP_ASSOC Type IDs */ ++#define BTA_TYPE_ID_MAC_ADDRESS 1 ++#define BTA_TYPE_ID_PREFERRED_CHANNELS 2 ++#define BTA_TYPE_ID_CONNECTED_CHANNELS 3 ++#define BTA_TYPE_ID_CAPABILITIES 4 ++#define BTA_TYPE_ID_VERSION 5 ++#endif /* _802_11_bta_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/802.11e.h b/drivers/net/wireless/ap6211/include/proto/802.11e.h +new file mode 100755 +index 0000000..f391e68 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/802.11e.h +@@ -0,0 +1,131 @@ ++/* ++ * 802.11e protocol header file ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: 802.11e.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _802_11e_H_ ++#define _802_11e_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++/* WME Traffic Specification (TSPEC) element */ ++#define WME_TSPEC_HDR_LEN 2 /* WME TSPEC header length */ ++#define WME_TSPEC_BODY_OFF 2 /* WME TSPEC body offset */ ++ ++#define WME_CATEGORY_CODE_OFFSET 0 /* WME Category code offset */ ++#define WME_ACTION_CODE_OFFSET 1 /* WME Action code offset */ ++#define WME_TOKEN_CODE_OFFSET 2 /* WME Token code offset */ ++#define WME_STATUS_CODE_OFFSET 3 /* WME Status code offset */ ++ ++BWL_PRE_PACKED_STRUCT struct tsinfo { ++ uint8 octets[3]; ++} BWL_POST_PACKED_STRUCT; ++ ++typedef struct tsinfo tsinfo_t; ++ ++/* 802.11e TSPEC IE */ ++typedef BWL_PRE_PACKED_STRUCT struct tspec { ++ uint8 oui[DOT11_OUI_LEN]; /* WME_OUI */ ++ uint8 type; /* WME_TYPE */ ++ uint8 subtype; /* WME_SUBTYPE_TSPEC */ ++ uint8 version; /* WME_VERSION */ ++ tsinfo_t tsinfo; /* TS Info bit field */ ++ uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ ++ uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ ++ uint32 min_srv_interval; /* Minimum Service Interval (us) */ ++ uint32 max_srv_interval; /* Maximum Service Interval (us) */ ++ uint32 inactivity_interval; /* Inactivity Interval (us) */ ++ uint32 suspension_interval; /* Suspension Interval (us) */ ++ uint32 srv_start_time; /* Service Start Time (us) */ ++ uint32 min_data_rate; /* Minimum Data Rate (bps) */ ++ uint32 mean_data_rate; /* Mean Data Rate (bps) */ ++ uint32 peak_data_rate; /* Peak Data Rate (bps) */ ++ uint32 max_burst_size; /* Maximum Burst Size (bytes) */ ++ uint32 delay_bound; /* Delay Bound (us) */ ++ uint32 min_phy_rate; /* Minimum PHY Rate (bps) */ ++ uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0-8.0) */ ++ uint16 medium_time; /* Medium Time (32 us/s periods) */ ++} BWL_POST_PACKED_STRUCT tspec_t; ++ ++#define WME_TSPEC_LEN (sizeof(tspec_t)) /* not including 2-bytes of header */ ++ ++/* ts_info */ ++/* 802.1D priority is duplicated - bits 13-11 AND bits 3-1 */ ++#define TS_INFO_TID_SHIFT 1 /* TS info. TID shift */ ++#define TS_INFO_TID_MASK (0xf << TS_INFO_TID_SHIFT) /* TS info. TID mask */ ++#define TS_INFO_CONTENTION_SHIFT 7 /* TS info. contention shift */ ++#define TS_INFO_CONTENTION_MASK (0x1 << TS_INFO_CONTENTION_SHIFT) /* TS info. contention mask */ ++#define TS_INFO_DIRECTION_SHIFT 5 /* TS info. direction shift */ ++#define TS_INFO_DIRECTION_MASK (0x3 << TS_INFO_DIRECTION_SHIFT) /* TS info. direction mask */ ++#define TS_INFO_PSB_SHIFT 2 /* TS info. PSB bit Shift */ ++#define TS_INFO_PSB_MASK (1 << TS_INFO_PSB_SHIFT) /* TS info. PSB mask */ ++#define TS_INFO_UPLINK (0 << TS_INFO_DIRECTION_SHIFT) /* TS info. uplink */ ++#define TS_INFO_DOWNLINK (1 << TS_INFO_DIRECTION_SHIFT) /* TS info. downlink */ ++#define TS_INFO_BIDIRECTIONAL (3 << TS_INFO_DIRECTION_SHIFT) /* TS info. bidirectional */ ++#define TS_INFO_USER_PRIO_SHIFT 3 /* TS info. user priority shift */ ++/* TS info. user priority mask */ ++#define TS_INFO_USER_PRIO_MASK (0x7 << TS_INFO_USER_PRIO_SHIFT) ++ ++/* Macro to get/set bit(s) field in TSINFO */ ++#define WLC_CAC_GET_TID(pt) ((((pt).octets[0]) & TS_INFO_TID_MASK) >> TS_INFO_TID_SHIFT) ++#define WLC_CAC_GET_DIR(pt) ((((pt).octets[0]) & \ ++ TS_INFO_DIRECTION_MASK) >> TS_INFO_DIRECTION_SHIFT) ++#define WLC_CAC_GET_PSB(pt) ((((pt).octets[1]) & TS_INFO_PSB_MASK) >> TS_INFO_PSB_SHIFT) ++#define WLC_CAC_GET_USER_PRIO(pt) ((((pt).octets[1]) & \ ++ TS_INFO_USER_PRIO_MASK) >> TS_INFO_USER_PRIO_SHIFT) ++ ++#define WLC_CAC_SET_TID(pt, id) ((((pt).octets[0]) & (~TS_INFO_TID_MASK)) | \ ++ ((id) << TS_INFO_TID_SHIFT)) ++#define WLC_CAC_SET_USER_PRIO(pt, prio) ((((pt).octets[0]) & (~TS_INFO_USER_PRIO_MASK)) | \ ++ ((prio) << TS_INFO_USER_PRIO_SHIFT)) ++ ++/* 802.11e QBSS Load IE */ ++#define QBSS_LOAD_IE_LEN 5 /* QBSS Load IE length */ ++#define QBSS_LOAD_AAC_OFF 3 /* AAC offset in IE */ ++ ++#define CAC_ADDTS_RESP_TIMEOUT 300 /* default ADDTS response timeout in ms */ ++ ++/* 802.11e ADDTS status code */ ++#define DOT11E_STATUS_ADMISSION_ACCEPTED 0 /* TSPEC Admission accepted status */ ++#define DOT11E_STATUS_ADDTS_INVALID_PARAM 1 /* TSPEC invalid parameter status */ ++#define DOT11E_STATUS_ADDTS_REFUSED_NSBW 3 /* ADDTS refused (non-sufficient BW) */ ++#define DOT11E_STATUS_ADDTS_REFUSED_AWHILE 47 /* ADDTS refused but could retry later */ ++ ++/* 802.11e DELTS status code */ ++#define DOT11E_STATUS_QSTA_LEAVE_QBSS 36 /* STA leave QBSS */ ++#define DOT11E_STATUS_END_TS 37 /* END TS */ ++#define DOT11E_STATUS_UNKNOWN_TS 38 /* UNKNOWN TS */ ++#define DOT11E_STATUS_QSTA_REQ_TIMEOUT 39 /* STA ADDTS request timeout */ ++ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _802_11e_CAC_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/802.1d.h b/drivers/net/wireless/ap6211/include/proto/802.1d.h +new file mode 100755 +index 0000000..f11cc6c +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/802.1d.h +@@ -0,0 +1,50 @@ ++/* ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * Fundamental types and constants relating to 802.1D ++ * ++ * $Id: 802.1d.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _802_1_D_ ++#define _802_1_D_ ++ ++/* 802.1D priority defines */ ++#define PRIO_8021D_NONE 2 /* None = - */ ++#define PRIO_8021D_BK 1 /* BK - Background */ ++#define PRIO_8021D_BE 0 /* BE - Best-effort */ ++#define PRIO_8021D_EE 3 /* EE - Excellent-effort */ ++#define PRIO_8021D_CL 4 /* CL - Controlled Load */ ++#define PRIO_8021D_VI 5 /* Vi - Video */ ++#define PRIO_8021D_VO 6 /* Vo - Voice */ ++#define PRIO_8021D_NC 7 /* NC - Network Control */ ++#define MAXPRIO 7 /* 0-7 */ ++#define NUMPRIO (MAXPRIO + 1) ++ ++#define ALLPRIO -1 /* All prioirty */ ++ ++/* Converts prio to precedence since the numerical value of ++ * PRIO_8021D_BE and PRIO_8021D_NONE are swapped. ++ */ ++#define PRIO2PREC(prio) \ ++ (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? ((prio^2)) : (prio)) ++ ++#endif /* _802_1_D__ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/bcmeth.h b/drivers/net/wireless/ap6211/include/proto/bcmeth.h +new file mode 100755 +index 0000000..91ae75c +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/bcmeth.h +@@ -0,0 +1,112 @@ ++/* ++ * Broadcom Ethernettype protocol definitions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcmeth.h 294352 2011-11-06 19:23:00Z $ ++ */ ++ ++/* ++ * Broadcom Ethernet protocol defines ++ */ ++ ++#ifndef _BCMETH_H_ ++#define _BCMETH_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++/* ETHER_TYPE_BRCM is defined in ethernet.h */ ++ ++/* ++ * Following the 2byte BRCM ether_type is a 16bit BRCM subtype field ++ * in one of two formats: (only subtypes 32768-65535 are in use now) ++ * ++ * subtypes 0-32767: ++ * 8 bit subtype (0-127) ++ * 8 bit length in bytes (0-255) ++ * ++ * subtypes 32768-65535: ++ * 16 bit big-endian subtype ++ * 16 bit big-endian length in bytes (0-65535) ++ * ++ * length is the number of additional bytes beyond the 4 or 6 byte header ++ * ++ * Reserved values: ++ * 0 reserved ++ * 5-15 reserved for iLine protocol assignments ++ * 17-126 reserved, assignable ++ * 127 reserved ++ * 32768 reserved ++ * 32769-65534 reserved, assignable ++ * 65535 reserved ++ */ ++ ++/* ++ * While adding the subtypes and their specific processing code make sure ++ * bcmeth_bcm_hdr_t is the first data structure in the user specific data structure definition ++ */ ++ ++#define BCMILCP_SUBTYPE_RATE 1 ++#define BCMILCP_SUBTYPE_LINK 2 ++#define BCMILCP_SUBTYPE_CSA 3 ++#define BCMILCP_SUBTYPE_LARQ 4 ++#define BCMILCP_SUBTYPE_VENDOR 5 ++#define BCMILCP_SUBTYPE_FLH 17 ++ ++#define BCMILCP_SUBTYPE_VENDOR_LONG 32769 ++#define BCMILCP_SUBTYPE_CERT 32770 ++#define BCMILCP_SUBTYPE_SES 32771 ++ ++ ++#define BCMILCP_BCM_SUBTYPE_RESERVED 0 ++#define BCMILCP_BCM_SUBTYPE_EVENT 1 ++#define BCMILCP_BCM_SUBTYPE_SES 2 ++/* ++ * The EAPOL type is not used anymore. Instead EAPOL messages are now embedded ++ * within BCMILCP_BCM_SUBTYPE_EVENT type messages ++ */ ++/* #define BCMILCP_BCM_SUBTYPE_EAPOL 3 */ ++#define BCMILCP_BCM_SUBTYPE_DPT 4 ++ ++#define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8 ++#define BCMILCP_BCM_SUBTYPEHDR_VERSION 0 ++ ++/* These fields are stored in network order */ ++typedef BWL_PRE_PACKED_STRUCT struct bcmeth_hdr ++{ ++ uint16 subtype; /* Vendor specific..32769 */ ++ uint16 length; ++ uint8 version; /* Version is 0 */ ++ uint8 oui[3]; /* Broadcom OUI */ ++ /* user specific Data */ ++ uint16 usr_subtype; ++} BWL_POST_PACKED_STRUCT bcmeth_hdr_t; ++ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _BCMETH_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/bcmevent.h b/drivers/net/wireless/ap6211/include/proto/bcmevent.h +new file mode 100755 +index 0000000..c439707 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/bcmevent.h +@@ -0,0 +1,368 @@ ++/* ++ * Broadcom Event protocol definitions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * Dependencies: proto/bcmeth.h ++ * ++ * $Id: bcmevent.h 374275 2012-12-12 11:44:18Z $ ++ * ++ */ ++ ++/* ++ * Broadcom Ethernet Events protocol defines ++ * ++ */ ++ ++#ifndef _BCMEVENT_H_ ++#define _BCMEVENT_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++#define BCM_EVENT_MSG_VERSION 2 /* wl_event_msg_t struct version */ ++#define BCM_MSG_IFNAME_MAX 16 /* max length of interface name */ ++ ++/* flags */ ++#define WLC_EVENT_MSG_LINK 0x01 /* link is up */ ++#define WLC_EVENT_MSG_FLUSHTXQ 0x02 /* flush tx queue on MIC error */ ++#define WLC_EVENT_MSG_GROUP 0x04 /* group MIC error */ ++#define WLC_EVENT_MSG_UNKBSS 0x08 /* unknown source bsscfg */ ++#define WLC_EVENT_MSG_UNKIF 0x10 /* unknown source OS i/f */ ++ ++/* these fields are stored in network order */ ++ ++/* version 1 */ ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ uint16 version; ++ uint16 flags; /* see flags below */ ++ uint32 event_type; /* Message (see below) */ ++ uint32 status; /* Status code (see below) */ ++ uint32 reason; /* Reason code (if applicable) */ ++ uint32 auth_type; /* WLC_E_AUTH */ ++ uint32 datalen; /* data buf */ ++ struct ether_addr addr; /* Station address (if applicable) */ ++ char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ ++} BWL_POST_PACKED_STRUCT wl_event_msg_v1_t; ++ ++/* the current version */ ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ uint16 version; ++ uint16 flags; /* see flags below */ ++ uint32 event_type; /* Message (see below) */ ++ uint32 status; /* Status code (see below) */ ++ uint32 reason; /* Reason code (if applicable) */ ++ uint32 auth_type; /* WLC_E_AUTH */ ++ uint32 datalen; /* data buf */ ++ struct ether_addr addr; /* Station address (if applicable) */ ++ char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ ++ uint8 ifidx; /* destination OS i/f index */ ++ uint8 bsscfgidx; /* source bsscfg index */ ++} BWL_POST_PACKED_STRUCT wl_event_msg_t; ++ ++/* used by driver msgs */ ++typedef BWL_PRE_PACKED_STRUCT struct bcm_event { ++ struct ether_header eth; ++ bcmeth_hdr_t bcm_hdr; ++ wl_event_msg_t event; ++ /* data portion follows */ ++} BWL_POST_PACKED_STRUCT bcm_event_t; ++ ++#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header)) ++ ++/* Event messages */ ++#define WLC_E_SET_SSID 0 /* indicates status of set SSID */ ++#define WLC_E_JOIN 1 /* differentiates join IBSS from found (WLC_E_START) IBSS */ ++#define WLC_E_START 2 /* STA founded an IBSS or AP started a BSS */ ++#define WLC_E_AUTH 3 /* 802.11 AUTH request */ ++#define WLC_E_AUTH_IND 4 /* 802.11 AUTH indication */ ++#define WLC_E_DEAUTH 5 /* 802.11 DEAUTH request */ ++#define WLC_E_DEAUTH_IND 6 /* 802.11 DEAUTH indication */ ++#define WLC_E_ASSOC 7 /* 802.11 ASSOC request */ ++#define WLC_E_ASSOC_IND 8 /* 802.11 ASSOC indication */ ++#define WLC_E_REASSOC 9 /* 802.11 REASSOC request */ ++#define WLC_E_REASSOC_IND 10 /* 802.11 REASSOC indication */ ++#define WLC_E_DISASSOC 11 /* 802.11 DISASSOC request */ ++#define WLC_E_DISASSOC_IND 12 /* 802.11 DISASSOC indication */ ++#define WLC_E_QUIET_START 13 /* 802.11h Quiet period started */ ++#define WLC_E_QUIET_END 14 /* 802.11h Quiet period ended */ ++#define WLC_E_BEACON_RX 15 /* BEACONS received/lost indication */ ++#define WLC_E_LINK 16 /* generic link indication */ ++#define WLC_E_MIC_ERROR 17 /* TKIP MIC error occurred */ ++#define WLC_E_NDIS_LINK 18 /* NDIS style link indication */ ++#define WLC_E_ROAM 19 /* roam attempt occurred: indicate status & reason */ ++#define WLC_E_TXFAIL 20 /* change in dot11FailedCount (txfail) */ ++#define WLC_E_PMKID_CACHE 21 /* WPA2 pmkid cache indication */ ++#define WLC_E_RETROGRADE_TSF 22 /* current AP's TSF value went backward */ ++#define WLC_E_PRUNE 23 /* AP was pruned from join list for reason */ ++#define WLC_E_AUTOAUTH 24 /* report AutoAuth table entry match for join attempt */ ++#define WLC_E_EAPOL_MSG 25 /* Event encapsulating an EAPOL message */ ++#define WLC_E_SCAN_COMPLETE 26 /* Scan results are ready or scan was aborted */ ++#define WLC_E_ADDTS_IND 27 /* indicate to host addts fail/success */ ++#define WLC_E_DELTS_IND 28 /* indicate to host delts fail/success */ ++#define WLC_E_BCNSENT_IND 29 /* indicate to host of beacon transmit */ ++#define WLC_E_BCNRX_MSG 30 /* Send the received beacon up to the host */ ++#define WLC_E_BCNLOST_MSG 31 /* indicate to host loss of beacon */ ++#define WLC_E_ROAM_PREP 32 /* before attempting to roam */ ++#define WLC_E_PFN_NET_FOUND 33 /* PFN network found event */ ++#define WLC_E_PFN_NET_LOST 34 /* PFN network lost event */ ++#define WLC_E_RESET_COMPLETE 35 ++#define WLC_E_JOIN_START 36 ++#define WLC_E_ROAM_START 37 ++#define WLC_E_ASSOC_START 38 ++#define WLC_E_IBSS_ASSOC 39 ++#define WLC_E_RADIO 40 ++#define WLC_E_PSM_WATCHDOG 41 /* PSM microcode watchdog fired */ ++#define WLC_E_PROBREQ_MSG 44 /* probe request received */ ++#define WLC_E_SCAN_CONFIRM_IND 45 ++#define WLC_E_PSK_SUP 46 /* WPA Handshake fail */ ++#define WLC_E_COUNTRY_CODE_CHANGED 47 ++#define WLC_E_EXCEEDED_MEDIUM_TIME 48 /* WMMAC excedded medium time */ ++#define WLC_E_ICV_ERROR 49 /* WEP ICV error occurred */ ++#define WLC_E_UNICAST_DECODE_ERROR 50 /* Unsupported unicast encrypted frame */ ++#define WLC_E_MULTICAST_DECODE_ERROR 51 /* Unsupported multicast encrypted frame */ ++#define WLC_E_TRACE 52 ++#ifdef WLBTAMP ++#define WLC_E_BTA_HCI_EVENT 53 /* BT-AMP HCI event */ ++#endif ++#define WLC_E_IF 54 /* I/F change (for dongle host notification) */ ++#define WLC_E_P2P_DISC_LISTEN_COMPLETE 55 /* listen state expires */ ++#define WLC_E_RSSI 56 /* indicate RSSI change based on configured levels */ ++#define WLC_E_PFN_SCAN_COMPLETE 57 /* PFN completed scan of network list */ ++#define WLC_E_EXTLOG_MSG 58 ++#define WLC_E_ACTION_FRAME 59 /* Action frame Rx */ ++#define WLC_E_ACTION_FRAME_COMPLETE 60 /* Action frame Tx complete */ ++#define WLC_E_PRE_ASSOC_IND 61 /* assoc request received */ ++#define WLC_E_PRE_REASSOC_IND 62 /* re-assoc request received */ ++#define WLC_E_CHANNEL_ADOPTED 63 ++#define WLC_E_AP_STARTED 64 /* AP started */ ++#define WLC_E_DFS_AP_STOP 65 /* AP stopped due to DFS */ ++#define WLC_E_DFS_AP_RESUME 66 /* AP resumed due to DFS */ ++#define WLC_E_WAI_STA_EVENT 67 /* WAI stations event */ ++#define WLC_E_WAI_MSG 68 /* event encapsulating an WAI message */ ++#define WLC_E_ESCAN_RESULT 69 /* escan result event */ ++#define WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 /* action frame off channel complete */ ++#define WLC_E_PROBRESP_MSG 71 /* probe response received */ ++#define WLC_E_P2P_PROBREQ_MSG 72 /* P2P Probe request received */ ++#define WLC_E_DCS_REQUEST 73 ++ ++#define WLC_E_FIFO_CREDIT_MAP 74 /* credits for D11 FIFOs. [AC0,AC1,AC2,AC3,BC_MC,ATIM] */ ++ ++#define WLC_E_ACTION_FRAME_RX 75 /* Received action frame event WITH ++ * wl_event_rx_frame_data_t header ++ */ ++#define WLC_E_WAKE_EVENT 76 /* Wake Event timer fired, used for wake WLAN test mode */ ++#define WLC_E_RM_COMPLETE 77 /* Radio measurement complete */ ++#define WLC_E_HTSFSYNC 78 /* Synchronize TSF with the host */ ++#define WLC_E_OVERLAY_REQ 79 /* request an overlay IOCTL/iovar from the host */ ++#define WLC_E_CSA_COMPLETE_IND 80 /* 802.11 CHANNEL SWITCH ACTION completed */ ++#define WLC_E_EXCESS_PM_WAKE_EVENT 81 /* excess PM Wake Event to inform host */ ++#define WLC_E_PFN_SCAN_NONE 82 /* no PFN networks around */ ++#define WLC_E_PFN_SCAN_ALLGONE 83 /* last found PFN network gets lost */ ++#define WLC_E_GTK_PLUMBED 84 ++#define WLC_E_ASSOC_IND_NDIS 85 /* 802.11 ASSOC indication for NDIS only */ ++#define WLC_E_REASSOC_IND_NDIS 86 /* 802.11 REASSOC indication for NDIS only */ ++#define WLC_E_ASSOC_REQ_IE 87 ++#define WLC_E_ASSOC_RESP_IE 88 ++#define WLC_E_ASSOC_RECREATED 89 /* association recreated on resume */ ++#define WLC_E_ACTION_FRAME_RX_NDIS 90 /* rx action frame event for NDIS only */ ++#define WLC_E_AUTH_REQ 91 /* authentication request received */ ++#define WLC_E_TDLS_PEER_EVENT 92 /* discovered peer, connected or disconnected peer */ ++#define WLC_E_SPEEDY_RECREATE_FAIL 93 /* fast assoc recreation failed */ ++#define WLC_E_SERVICE_FOUND 102 /* desired service found */ ++#define WLC_E_GAS_FRAGMENT_RX 103 /* GAS fragment received */ ++#define WLC_E_GAS_COMPLETE 104 /* GAS sessions all complete */ ++#define WLC_E_P2PO_ADD_DEVICE 105 /* New device found by p2p offload */ ++#define WLC_E_P2PO_DEL_DEVICE 106 /* device has been removed by p2p offload */ ++#define WLC_E_LAST 107 /* highest val + 1 for range checking */ ++ ++ ++/* Table of event name strings for UIs and debugging dumps */ ++typedef struct { ++ uint event; ++ const char *name; ++} bcmevent_name_t; ++ ++extern const bcmevent_name_t bcmevent_names[]; ++extern const int bcmevent_names_size; ++ ++/* Event status codes */ ++#define WLC_E_STATUS_SUCCESS 0 /* operation was successful */ ++#define WLC_E_STATUS_FAIL 1 /* operation failed */ ++#define WLC_E_STATUS_TIMEOUT 2 /* operation timed out */ ++#define WLC_E_STATUS_NO_NETWORKS 3 /* failed due to no matching network found */ ++#define WLC_E_STATUS_ABORT 4 /* operation was aborted */ ++#define WLC_E_STATUS_NO_ACK 5 /* protocol failure: packet not ack'd */ ++#define WLC_E_STATUS_UNSOLICITED 6 /* AUTH or ASSOC packet was unsolicited */ ++#define WLC_E_STATUS_ATTEMPT 7 /* attempt to assoc to an auto auth configuration */ ++#define WLC_E_STATUS_PARTIAL 8 /* scan results are incomplete */ ++#define WLC_E_STATUS_NEWSCAN 9 /* scan aborted by another scan */ ++#define WLC_E_STATUS_NEWASSOC 10 /* scan aborted due to assoc in progress */ ++#define WLC_E_STATUS_11HQUIET 11 /* 802.11h quiet period started */ ++#define WLC_E_STATUS_SUPPRESS 12 /* user disabled scanning (WLC_SET_SCANSUPPRESS) */ ++#define WLC_E_STATUS_NOCHANS 13 /* no allowable channels to scan */ ++#define WLC_E_STATUS_CS_ABORT 15 /* abort channel select */ ++#define WLC_E_STATUS_ERROR 16 /* request failed due to error */ ++ ++/* roam reason codes */ ++#define WLC_E_REASON_INITIAL_ASSOC 0 /* initial assoc */ ++#define WLC_E_REASON_LOW_RSSI 1 /* roamed due to low RSSI */ ++#define WLC_E_REASON_DEAUTH 2 /* roamed due to DEAUTH indication */ ++#define WLC_E_REASON_DISASSOC 3 /* roamed due to DISASSOC indication */ ++#define WLC_E_REASON_BCNS_LOST 4 /* roamed due to lost beacons */ ++#define WLC_E_REASON_MINTXRATE 9 /* roamed because at mintxrate for too long */ ++#define WLC_E_REASON_TXFAIL 10 /* We can hear AP, but AP can't hear us */ ++ ++/* Roam codes used primarily by CCX */ ++#define WLC_E_REASON_FAST_ROAM_FAILED 5 /* roamed due to fast roam failure */ ++#define WLC_E_REASON_DIRECTED_ROAM 6 /* roamed due to request by AP */ ++#define WLC_E_REASON_TSPEC_REJECTED 7 /* roamed due to TSPEC rejection */ ++#define WLC_E_REASON_BETTER_AP 8 /* roamed due to finding better AP */ ++ ++ ++#define WLC_E_REASON_REQUESTED_ROAM 11 /* roamed due to BSS Mgmt Transition request by AP */ ++ ++/* prune reason codes */ ++#define WLC_E_PRUNE_ENCR_MISMATCH 1 /* encryption mismatch */ ++#define WLC_E_PRUNE_BCAST_BSSID 2 /* AP uses a broadcast BSSID */ ++#define WLC_E_PRUNE_MAC_DENY 3 /* STA's MAC addr is in AP's MAC deny list */ ++#define WLC_E_PRUNE_MAC_NA 4 /* STA's MAC addr is not in AP's MAC allow list */ ++#define WLC_E_PRUNE_REG_PASSV 5 /* AP not allowed due to regulatory restriction */ ++#define WLC_E_PRUNE_SPCT_MGMT 6 /* AP does not support STA locale spectrum mgmt */ ++#define WLC_E_PRUNE_RADAR 7 /* AP is on a radar channel of STA locale */ ++#define WLC_E_RSN_MISMATCH 8 /* STA does not support AP's RSN */ ++#define WLC_E_PRUNE_NO_COMMON_RATES 9 /* No rates in common with AP */ ++#define WLC_E_PRUNE_BASIC_RATES 10 /* STA does not support all basic rates of BSS */ ++#define WLC_E_PRUNE_CIPHER_NA 12 /* BSS's cipher not supported */ ++#define WLC_E_PRUNE_KNOWN_STA 13 /* AP is already known to us as a STA */ ++#define WLC_E_PRUNE_WDS_PEER 15 /* AP is already known to us as a WDS peer */ ++#define WLC_E_PRUNE_QBSS_LOAD 16 /* QBSS LOAD - AAC is too low */ ++#define WLC_E_PRUNE_HOME_AP 17 /* prune home AP */ ++ ++/* WPA failure reason codes carried in the WLC_E_PSK_SUP event */ ++#define WLC_E_SUP_OTHER 0 /* Other reason */ ++#define WLC_E_SUP_DECRYPT_KEY_DATA 1 /* Decryption of key data failed */ ++#define WLC_E_SUP_BAD_UCAST_WEP128 2 /* Illegal use of ucast WEP128 */ ++#define WLC_E_SUP_BAD_UCAST_WEP40 3 /* Illegal use of ucast WEP40 */ ++#define WLC_E_SUP_UNSUP_KEY_LEN 4 /* Unsupported key length */ ++#define WLC_E_SUP_PW_KEY_CIPHER 5 /* Unicast cipher mismatch in pairwise key */ ++#define WLC_E_SUP_MSG3_TOO_MANY_IE 6 /* WPA IE contains > 1 RSN IE in key msg 3 */ ++#define WLC_E_SUP_MSG3_IE_MISMATCH 7 /* WPA IE mismatch in key message 3 */ ++#define WLC_E_SUP_NO_INSTALL_FLAG 8 /* INSTALL flag unset in 4-way msg */ ++#define WLC_E_SUP_MSG3_NO_GTK 9 /* encapsulated GTK missing from msg 3 */ ++#define WLC_E_SUP_GRP_KEY_CIPHER 10 /* Multicast cipher mismatch in group key */ ++#define WLC_E_SUP_GRP_MSG1_NO_GTK 11 /* encapsulated GTK missing from group msg 1 */ ++#define WLC_E_SUP_GTK_DECRYPT_FAIL 12 /* GTK decrypt failure */ ++#define WLC_E_SUP_SEND_FAIL 13 /* message send failure */ ++#define WLC_E_SUP_DEAUTH 14 /* received FC_DEAUTH */ ++#define WLC_E_SUP_WPA_PSK_TMO 15 /* WPA PSK 4-way handshake timeout */ ++ ++/* Event data for events that include frames received over the air */ ++/* WLC_E_PROBRESP_MSG ++ * WLC_E_P2P_PROBREQ_MSG ++ * WLC_E_ACTION_FRAME_RX ++ */ ++typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data { ++ uint16 version; ++ uint16 channel; /* Matches chanspec_t format from bcmwifi_channels.h */ ++ int32 rssi; ++ uint32 mactime; ++ uint32 rate; ++} BWL_POST_PACKED_STRUCT wl_event_rx_frame_data_t; ++ ++#define BCM_RX_FRAME_DATA_VERSION 1 ++ ++/* WLC_E_IF event data */ ++typedef struct wl_event_data_if { ++ uint8 ifidx; /* RTE virtual device index (for dongle) */ ++ uint8 opcode; /* see I/F opcode */ ++ uint8 reserved; ++ uint8 bssidx; /* bsscfg index */ ++ uint8 role; /* see I/F role */ ++} wl_event_data_if_t; ++ ++/* opcode in WLC_E_IF event */ ++#define WLC_E_IF_ADD 1 /* bsscfg add */ ++#define WLC_E_IF_DEL 2 /* bsscfg delete */ ++#define WLC_E_IF_CHANGE 3 /* bsscfg role change */ ++ ++/* I/F role code in WLC_E_IF event */ ++#define WLC_E_IF_ROLE_STA 0 /* Infra STA */ ++#define WLC_E_IF_ROLE_AP 1 /* Access Point */ ++#define WLC_E_IF_ROLE_WDS 2 /* WDS link */ ++#define WLC_E_IF_ROLE_P2P_GO 3 /* P2P Group Owner */ ++#define WLC_E_IF_ROLE_P2P_CLIENT 4 /* P2P Client */ ++#ifdef WLBTAMP ++#define WLC_E_IF_ROLE_BTA_CREATOR 5 /* BT-AMP Creator */ ++#define WLC_E_IF_ROLE_BTA_ACCEPTOR 6 /* BT-AMP Acceptor */ ++#endif ++ ++/* Reason codes for LINK */ ++#define WLC_E_LINK_BCN_LOSS 1 /* Link down because of beacon loss */ ++#define WLC_E_LINK_DISASSOC 2 /* Link down because of disassoc */ ++#define WLC_E_LINK_ASSOC_REC 3 /* Link down because assoc recreate failed */ ++#define WLC_E_LINK_BSSCFG_DIS 4 /* Link down due to bsscfg down */ ++ ++/* reason codes for WLC_E_OVERLAY_REQ event */ ++#define WLC_E_OVL_DOWNLOAD 0 /* overlay download request */ ++#define WLC_E_OVL_UPDATE_IND 1 /* device indication of host overlay update */ ++ ++/* reason codes for WLC_E_TDLS_PEER_EVENT event */ ++#define WLC_E_TDLS_PEER_DISCOVERED 0 /* peer is ready to establish TDLS */ ++#define WLC_E_TDLS_PEER_CONNECTED 1 ++#define WLC_E_TDLS_PEER_DISCONNECTED 2 ++ ++/* GAS event data */ ++typedef BWL_PRE_PACKED_STRUCT struct wl_event_gas { ++ uint16 channel; /* channel of GAS protocol */ ++ uint8 dialog_token; /* GAS dialog token */ ++ uint8 fragment_id; /* fragment id */ ++ uint16 status_code; /* status code on GAS completion */ ++ uint16 data_len; /* length of data to follow */ ++ uint8 data[1]; /* variable length specified by data_len */ ++} BWL_POST_PACKED_STRUCT wl_event_gas_t; ++ ++/* service discovery TLV */ ++typedef BWL_PRE_PACKED_STRUCT struct wl_sd_tlv { ++ uint16 length; /* length of response_data */ ++ uint8 protocol; /* service protocol type */ ++ uint8 transaction_id; /* service transaction id */ ++ uint8 status_code; /* status code */ ++ uint8 data[1]; /* response data */ ++} BWL_POST_PACKED_STRUCT wl_sd_tlv_t; ++ ++/* service discovery event data */ ++typedef BWL_PRE_PACKED_STRUCT struct wl_event_sd { ++ uint16 channel; /* channel */ ++ uint8 count; /* number of tlvs */ ++ wl_sd_tlv_t tlv[1]; /* service discovery TLV */ ++} BWL_POST_PACKED_STRUCT wl_event_sd_t; ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _BCMEVENT_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/bcmip.h b/drivers/net/wireless/ap6211/include/proto/bcmip.h +new file mode 100755 +index 0000000..52cd71d +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/bcmip.h +@@ -0,0 +1,210 @@ ++/* ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * Fundamental constants relating to IP Protocol ++ * ++ * $Id: bcmip.h 290206 2011-10-17 19:13:51Z $ ++ */ ++ ++#ifndef _bcmip_h_ ++#define _bcmip_h_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++/* IPV4 and IPV6 common */ ++#define IP_VER_OFFSET 0x0 /* offset to version field */ ++#define IP_VER_MASK 0xf0 /* version mask */ ++#define IP_VER_SHIFT 4 /* version shift */ ++#define IP_VER_4 4 /* version number for IPV4 */ ++#define IP_VER_6 6 /* version number for IPV6 */ ++ ++#define IP_VER(ip_body) \ ++ ((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT) ++ ++#define IP_PROT_ICMP 0x1 /* ICMP protocol */ ++#define IP_PROT_IGMP 0x2 /* IGMP protocol */ ++#define IP_PROT_TCP 0x6 /* TCP protocol */ ++#define IP_PROT_UDP 0x11 /* UDP protocol type */ ++#define IP_PROT_ICMP6 0x3a /* ICMPv6 protocol type */ ++ ++/* IPV4 field offsets */ ++#define IPV4_VER_HL_OFFSET 0 /* version and ihl byte offset */ ++#define IPV4_TOS_OFFSET 1 /* type of service offset */ ++#define IPV4_PKTLEN_OFFSET 2 /* packet length offset */ ++#define IPV4_PKTFLAG_OFFSET 6 /* more-frag,dont-frag flag offset */ ++#define IPV4_PROT_OFFSET 9 /* protocol type offset */ ++#define IPV4_CHKSUM_OFFSET 10 /* IP header checksum offset */ ++#define IPV4_SRC_IP_OFFSET 12 /* src IP addr offset */ ++#define IPV4_DEST_IP_OFFSET 16 /* dest IP addr offset */ ++#define IPV4_OPTIONS_OFFSET 20 /* IP options offset */ ++ ++/* IPV4 field decodes */ ++#define IPV4_VER_MASK 0xf0 /* IPV4 version mask */ ++#define IPV4_VER_SHIFT 4 /* IPV4 version shift */ ++ ++#define IPV4_HLEN_MASK 0x0f /* IPV4 header length mask */ ++#define IPV4_HLEN(ipv4_body) (4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK)) ++ ++#define IPV4_ADDR_LEN 4 /* IPV4 address length */ ++ ++#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \ ++ ((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0) ++ ++#define IPV4_ADDR_BCAST(a) ((((uint8 *)(a))[0] & ((uint8 *)(a))[1] & \ ++ ((uint8 *)(a))[2] & ((uint8 *)(a))[3]) == 0xff) ++ ++#define IPV4_TOS_DSCP_MASK 0xfc /* DiffServ codepoint mask */ ++#define IPV4_TOS_DSCP_SHIFT 2 /* DiffServ codepoint shift */ ++ ++#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET]) ++ ++#define IPV4_TOS_PREC_MASK 0xe0 /* Historical precedence mask */ ++#define IPV4_TOS_PREC_SHIFT 5 /* Historical precedence shift */ ++ ++#define IPV4_TOS_LOWDELAY 0x10 /* Lowest delay requested */ ++#define IPV4_TOS_THROUGHPUT 0x8 /* Best throughput requested */ ++#define IPV4_TOS_RELIABILITY 0x4 /* Most reliable delivery requested */ ++ ++#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET]) ++ ++#define IPV4_FRAG_RESV 0x8000 /* Reserved */ ++#define IPV4_FRAG_DONT 0x4000 /* Don't fragment */ ++#define IPV4_FRAG_MORE 0x2000 /* More fragments */ ++#define IPV4_FRAG_OFFSET_MASK 0x1fff /* Fragment offset */ ++ ++#define IPV4_ADDR_STR_LEN 16 /* Max IP address length in string format */ ++ ++/* IPV4 packet formats */ ++BWL_PRE_PACKED_STRUCT struct ipv4_addr { ++ uint8 addr[IPV4_ADDR_LEN]; ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct ipv4_hdr { ++ uint8 version_ihl; /* Version and Internet Header Length */ ++ uint8 tos; /* Type Of Service */ ++ uint16 tot_len; /* Number of bytes in packet (max 65535) */ ++ uint16 id; ++ uint16 frag; /* 3 flag bits and fragment offset */ ++ uint8 ttl; /* Time To Live */ ++ uint8 prot; /* Protocol */ ++ uint16 hdr_chksum; /* IP header checksum */ ++ uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */ ++ uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */ ++} BWL_POST_PACKED_STRUCT; ++ ++/* IPV6 field offsets */ ++#define IPV6_PAYLOAD_LEN_OFFSET 4 /* payload length offset */ ++#define IPV6_NEXT_HDR_OFFSET 6 /* next header/protocol offset */ ++#define IPV6_HOP_LIMIT_OFFSET 7 /* hop limit offset */ ++#define IPV6_SRC_IP_OFFSET 8 /* src IP addr offset */ ++#define IPV6_DEST_IP_OFFSET 24 /* dst IP addr offset */ ++ ++/* IPV6 field decodes */ ++#define IPV6_TRAFFIC_CLASS(ipv6_body) \ ++ (((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \ ++ ((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4)) ++ ++#define IPV6_FLOW_LABEL(ipv6_body) \ ++ (((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \ ++ (((uint8 *)(ipv6_body))[2] << 8) | \ ++ (((uint8 *)(ipv6_body))[3])) ++ ++#define IPV6_PAYLOAD_LEN(ipv6_body) \ ++ ((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \ ++ ((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1]) ++ ++#define IPV6_NEXT_HDR(ipv6_body) \ ++ (((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET]) ++ ++#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body) ++ ++#define IPV6_ADDR_LEN 16 /* IPV6 address length */ ++ ++/* IPV4 TOS or IPV6 Traffic Classifier or 0 */ ++#define IP_TOS46(ip_body) \ ++ (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \ ++ IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0) ++ ++/* IPV6 extension headers (options) */ ++#define IPV6_EXTHDR_HOP 0 ++#define IPV6_EXTHDR_ROUTING 43 ++#define IPV6_EXTHDR_FRAGMENT 44 ++#define IPV6_EXTHDR_AUTH 51 ++#define IPV6_EXTHDR_NONE 59 ++#define IPV6_EXTHDR_DEST 60 ++ ++#define IPV6_EXTHDR(prot) (((prot) == IPV6_EXTHDR_HOP) || \ ++ ((prot) == IPV6_EXTHDR_ROUTING) || \ ++ ((prot) == IPV6_EXTHDR_FRAGMENT) || \ ++ ((prot) == IPV6_EXTHDR_AUTH) || \ ++ ((prot) == IPV6_EXTHDR_NONE) || \ ++ ((prot) == IPV6_EXTHDR_DEST)) ++ ++#define IPV6_MIN_HLEN 40 ++ ++#define IPV6_EXTHDR_LEN(eh) ((((struct ipv6_exthdr *)(eh))->hdrlen + 1) << 3) ++ ++BWL_PRE_PACKED_STRUCT struct ipv6_exthdr { ++ uint8 nexthdr; ++ uint8 hdrlen; ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct ipv6_exthdr_frag { ++ uint8 nexthdr; ++ uint8 rsvd; ++ uint16 frag_off; ++ uint32 ident; ++} BWL_POST_PACKED_STRUCT; ++ ++static INLINE int32 ++ipv6_exthdr_len(uint8 *h, uint8 *proto) ++{ ++ uint16 len = 0, hlen; ++ struct ipv6_exthdr *eh = (struct ipv6_exthdr *)h; ++ ++ while (IPV6_EXTHDR(eh->nexthdr)) { ++ if (eh->nexthdr == IPV6_EXTHDR_NONE) ++ return -1; ++ else if (eh->nexthdr == IPV6_EXTHDR_FRAGMENT) ++ hlen = 8; ++ else if (eh->nexthdr == IPV6_EXTHDR_AUTH) ++ hlen = (eh->hdrlen + 2) << 2; ++ else ++ hlen = IPV6_EXTHDR_LEN(eh); ++ ++ len += hlen; ++ eh = (struct ipv6_exthdr *)(h + len); ++ } ++ ++ *proto = eh->nexthdr; ++ return len; ++} ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _bcmip_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/bt_amp_hci.h b/drivers/net/wireless/ap6211/include/proto/bt_amp_hci.h +new file mode 100755 +index 0000000..8617985 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/bt_amp_hci.h +@@ -0,0 +1,441 @@ ++/* ++ * BT-AMP (BlueTooth Alternate Mac and Phy) HCI (Host/Controller Interface) ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bt_amp_hci.h 294267 2011-11-04 23:41:52Z $ ++*/ ++ ++#ifndef _bt_amp_hci_h ++#define _bt_amp_hci_h ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++/* AMP HCI CMD packet format */ ++typedef BWL_PRE_PACKED_STRUCT struct amp_hci_cmd { ++ uint16 opcode; ++ uint8 plen; ++ uint8 parms[1]; ++} BWL_POST_PACKED_STRUCT amp_hci_cmd_t; ++ ++#define HCI_CMD_PREAMBLE_SIZE OFFSETOF(amp_hci_cmd_t, parms) ++#define HCI_CMD_DATA_SIZE 255 ++ ++/* AMP HCI CMD opcode layout */ ++#define HCI_CMD_OPCODE(ogf, ocf) ((((ogf) & 0x3F) << 10) | ((ocf) & 0x03FF)) ++#define HCI_CMD_OGF(opcode) ((uint8)(((opcode) >> 10) & 0x3F)) ++#define HCI_CMD_OCF(opcode) ((opcode) & 0x03FF) ++ ++/* AMP HCI command opcodes */ ++#define HCI_Read_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0001) ++#define HCI_Reset_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0002) ++#define HCI_Read_Link_Quality HCI_CMD_OPCODE(0x05, 0x0003) ++#define HCI_Read_Local_AMP_Info HCI_CMD_OPCODE(0x05, 0x0009) ++#define HCI_Read_Local_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000A) ++#define HCI_Write_Remote_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000B) ++#define HCI_Create_Physical_Link HCI_CMD_OPCODE(0x01, 0x0035) ++#define HCI_Accept_Physical_Link_Request HCI_CMD_OPCODE(0x01, 0x0036) ++#define HCI_Disconnect_Physical_Link HCI_CMD_OPCODE(0x01, 0x0037) ++#define HCI_Create_Logical_Link HCI_CMD_OPCODE(0x01, 0x0038) ++#define HCI_Accept_Logical_Link HCI_CMD_OPCODE(0x01, 0x0039) ++#define HCI_Disconnect_Logical_Link HCI_CMD_OPCODE(0x01, 0x003A) ++#define HCI_Logical_Link_Cancel HCI_CMD_OPCODE(0x01, 0x003B) ++#define HCI_Flow_Spec_Modify HCI_CMD_OPCODE(0x01, 0x003C) ++#define HCI_Write_Flow_Control_Mode HCI_CMD_OPCODE(0x01, 0x0067) ++#define HCI_Read_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x0069) ++#define HCI_Write_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x006A) ++#define HCI_Short_Range_Mode HCI_CMD_OPCODE(0x01, 0x006B) ++#define HCI_Reset HCI_CMD_OPCODE(0x03, 0x0003) ++#define HCI_Read_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0015) ++#define HCI_Write_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0016) ++#define HCI_Read_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0036) ++#define HCI_Write_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0037) ++#define HCI_Enhanced_Flush HCI_CMD_OPCODE(0x03, 0x005F) ++#define HCI_Read_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0061) ++#define HCI_Write_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0062) ++#define HCI_Set_Event_Mask_Page_2 HCI_CMD_OPCODE(0x03, 0x0063) ++#define HCI_Read_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0064) ++#define HCI_Write_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0065) ++#define HCI_Read_Local_Version_Info HCI_CMD_OPCODE(0x04, 0x0001) ++#define HCI_Read_Local_Supported_Commands HCI_CMD_OPCODE(0x04, 0x0002) ++#define HCI_Read_Buffer_Size HCI_CMD_OPCODE(0x04, 0x0005) ++#define HCI_Read_Data_Block_Size HCI_CMD_OPCODE(0x04, 0x000A) ++ ++/* AMP HCI command parameters */ ++typedef BWL_PRE_PACKED_STRUCT struct read_local_cmd_parms { ++ uint8 plh; ++ uint8 offset[2]; /* length so far */ ++ uint8 max_remote[2]; ++} BWL_POST_PACKED_STRUCT read_local_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct write_remote_cmd_parms { ++ uint8 plh; ++ uint8 offset[2]; ++ uint8 len[2]; ++ uint8 frag[1]; ++} BWL_POST_PACKED_STRUCT write_remote_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct phy_link_cmd_parms { ++ uint8 plh; ++ uint8 key_length; ++ uint8 key_type; ++ uint8 key[1]; ++} BWL_POST_PACKED_STRUCT phy_link_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_cmd_parms { ++ uint8 plh; ++ uint8 reason; ++} BWL_POST_PACKED_STRUCT dis_phy_link_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct log_link_cmd_parms { ++ uint8 plh; ++ uint8 txflow[16]; ++ uint8 rxflow[16]; ++} BWL_POST_PACKED_STRUCT log_link_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct ext_flow_spec { ++ uint8 id; ++ uint8 service_type; ++ uint8 max_sdu[2]; ++ uint8 sdu_ia_time[4]; ++ uint8 access_latency[4]; ++ uint8 flush_timeout[4]; ++} BWL_POST_PACKED_STRUCT ext_flow_spec_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_cmd_parms { ++ uint8 plh; ++ uint8 tx_fs_ID; ++} BWL_POST_PACKED_STRUCT log_link_cancel_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_cmd_parms { ++ uint8 llh[2]; ++ uint8 txflow[16]; ++ uint8 rxflow[16]; ++} BWL_POST_PACKED_STRUCT flow_spec_mod_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct plh_pad { ++ uint8 plh; ++ uint8 pad; ++} BWL_POST_PACKED_STRUCT plh_pad_t; ++ ++typedef BWL_PRE_PACKED_STRUCT union hci_handle { ++ uint16 bredr; ++ plh_pad_t amp; ++} BWL_POST_PACKED_STRUCT hci_handle_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct ls_to_cmd_parms { ++ hci_handle_t handle; ++ uint8 timeout[2]; ++} BWL_POST_PACKED_STRUCT ls_to_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct befto_cmd_parms { ++ uint8 llh[2]; ++ uint8 befto[4]; ++} BWL_POST_PACKED_STRUCT befto_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct srm_cmd_parms { ++ uint8 plh; ++ uint8 srm; ++} BWL_POST_PACKED_STRUCT srm_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct ld_cmd_parms { ++ uint8 ld_aware; ++ uint8 ld[2]; ++ uint8 ld_opts; ++ uint8 l_opts; ++} BWL_POST_PACKED_STRUCT ld_cmd_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct eflush_cmd_parms { ++ uint8 llh[2]; ++ uint8 packet_type; ++} BWL_POST_PACKED_STRUCT eflush_cmd_parms_t; ++ ++/* Generic AMP extended flow spec service types */ ++#define EFS_SVCTYPE_NO_TRAFFIC 0 ++#define EFS_SVCTYPE_BEST_EFFORT 1 ++#define EFS_SVCTYPE_GUARANTEED 2 ++ ++/* AMP HCI event packet format */ ++typedef BWL_PRE_PACKED_STRUCT struct amp_hci_event { ++ uint8 ecode; ++ uint8 plen; ++ uint8 parms[1]; ++} BWL_POST_PACKED_STRUCT amp_hci_event_t; ++ ++#define HCI_EVT_PREAMBLE_SIZE OFFSETOF(amp_hci_event_t, parms) ++ ++/* AMP HCI event codes */ ++#define HCI_Command_Complete 0x0E ++#define HCI_Command_Status 0x0F ++#define HCI_Flush_Occurred 0x11 ++#define HCI_Enhanced_Flush_Complete 0x39 ++#define HCI_Physical_Link_Complete 0x40 ++#define HCI_Channel_Select 0x41 ++#define HCI_Disconnect_Physical_Link_Complete 0x42 ++#define HCI_Logical_Link_Complete 0x45 ++#define HCI_Disconnect_Logical_Link_Complete 0x46 ++#define HCI_Flow_Spec_Modify_Complete 0x47 ++#define HCI_Number_of_Completed_Data_Blocks 0x48 ++#define HCI_Short_Range_Mode_Change_Complete 0x4C ++#define HCI_Status_Change_Event 0x4D ++#define HCI_Vendor_Specific 0xFF ++ ++/* AMP HCI event mask bit positions */ ++#define HCI_Physical_Link_Complete_Event_Mask 0x0001 ++#define HCI_Channel_Select_Event_Mask 0x0002 ++#define HCI_Disconnect_Physical_Link_Complete_Event_Mask 0x0004 ++#define HCI_Logical_Link_Complete_Event_Mask 0x0020 ++#define HCI_Disconnect_Logical_Link_Complete_Event_Mask 0x0040 ++#define HCI_Flow_Spec_Modify_Complete_Event_Mask 0x0080 ++#define HCI_Number_of_Completed_Data_Blocks_Event_Mask 0x0100 ++#define HCI_Short_Range_Mode_Change_Complete_Event_Mask 0x1000 ++#define HCI_Status_Change_Event_Mask 0x2000 ++#define HCI_All_Event_Mask 0x31e7 ++/* AMP HCI event parameters */ ++typedef BWL_PRE_PACKED_STRUCT struct cmd_status_parms { ++ uint8 status; ++ uint8 cmdpkts; ++ uint16 opcode; ++} BWL_POST_PACKED_STRUCT cmd_status_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct cmd_complete_parms { ++ uint8 cmdpkts; ++ uint16 opcode; ++ uint8 parms[1]; ++} BWL_POST_PACKED_STRUCT cmd_complete_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct flush_occurred_evt_parms { ++ uint16 handle; ++} BWL_POST_PACKED_STRUCT flush_occurred_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct write_remote_evt_parms { ++ uint8 status; ++ uint8 plh; ++} BWL_POST_PACKED_STRUCT write_remote_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct read_local_evt_parms { ++ uint8 status; ++ uint8 plh; ++ uint16 len; ++ uint8 frag[1]; ++} BWL_POST_PACKED_STRUCT read_local_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct read_local_info_evt_parms { ++ uint8 status; ++ uint8 AMP_status; ++ uint32 bandwidth; ++ uint32 gbandwidth; ++ uint32 latency; ++ uint32 PDU_size; ++ uint8 ctrl_type; ++ uint16 PAL_cap; ++ uint16 AMP_ASSOC_len; ++ uint32 max_flush_timeout; ++ uint32 be_flush_timeout; ++} BWL_POST_PACKED_STRUCT read_local_info_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct log_link_evt_parms { ++ uint8 status; ++ uint16 llh; ++ uint8 plh; ++ uint8 tx_fs_ID; ++} BWL_POST_PACKED_STRUCT log_link_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct disc_log_link_evt_parms { ++ uint8 status; ++ uint16 llh; ++ uint8 reason; ++} BWL_POST_PACKED_STRUCT disc_log_link_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_evt_parms { ++ uint8 status; ++ uint8 plh; ++ uint8 tx_fs_ID; ++} BWL_POST_PACKED_STRUCT log_link_cancel_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_evt_parms { ++ uint8 status; ++ uint16 llh; ++} BWL_POST_PACKED_STRUCT flow_spec_mod_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct phy_link_evt_parms { ++ uint8 status; ++ uint8 plh; ++} BWL_POST_PACKED_STRUCT phy_link_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_evt_parms { ++ uint8 status; ++ uint8 plh; ++ uint8 reason; ++} BWL_POST_PACKED_STRUCT dis_phy_link_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct read_ls_to_evt_parms { ++ uint8 status; ++ hci_handle_t handle; ++ uint16 timeout; ++} BWL_POST_PACKED_STRUCT read_ls_to_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct read_lla_ca_to_evt_parms { ++ uint8 status; ++ uint16 timeout; ++} BWL_POST_PACKED_STRUCT read_lla_ca_to_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct read_data_block_size_evt_parms { ++ uint8 status; ++ uint16 ACL_pkt_len; ++ uint16 data_block_len; ++ uint16 data_block_num; ++} BWL_POST_PACKED_STRUCT read_data_block_size_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct data_blocks { ++ uint16 handle; ++ uint16 pkts; ++ uint16 blocks; ++} BWL_POST_PACKED_STRUCT data_blocks_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct num_completed_data_blocks_evt_parms { ++ uint16 num_blocks; ++ uint8 num_handles; ++ data_blocks_t completed[1]; ++} BWL_POST_PACKED_STRUCT num_completed_data_blocks_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct befto_evt_parms { ++ uint8 status; ++ uint32 befto; ++} BWL_POST_PACKED_STRUCT befto_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct srm_evt_parms { ++ uint8 status; ++ uint8 plh; ++ uint8 srm; ++} BWL_POST_PACKED_STRUCT srm_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct contact_counter_evt_parms { ++ uint8 status; ++ uint8 llh[2]; ++ uint16 counter; ++} BWL_POST_PACKED_STRUCT contact_counter_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct contact_counter_reset_evt_parms { ++ uint8 status; ++ uint8 llh[2]; ++} BWL_POST_PACKED_STRUCT contact_counter_reset_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct read_linkq_evt_parms { ++ uint8 status; ++ hci_handle_t handle; ++ uint8 link_quality; ++} BWL_POST_PACKED_STRUCT read_linkq_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct ld_evt_parms { ++ uint8 status; ++ uint8 ld_aware; ++ uint8 ld[2]; ++ uint8 ld_opts; ++ uint8 l_opts; ++} BWL_POST_PACKED_STRUCT ld_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct eflush_complete_evt_parms { ++ uint16 handle; ++} BWL_POST_PACKED_STRUCT eflush_complete_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct vendor_specific_evt_parms { ++ uint8 len; ++ uint8 parms[1]; ++} BWL_POST_PACKED_STRUCT vendor_specific_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct local_version_info_evt_parms { ++ uint8 status; ++ uint8 hci_version; ++ uint16 hci_revision; ++ uint8 pal_version; ++ uint16 mfg_name; ++ uint16 pal_subversion; ++} BWL_POST_PACKED_STRUCT local_version_info_evt_parms_t; ++ ++#define MAX_SUPPORTED_CMD_BYTE 64 ++typedef BWL_PRE_PACKED_STRUCT struct local_supported_cmd_evt_parms { ++ uint8 status; ++ uint8 cmd[MAX_SUPPORTED_CMD_BYTE]; ++} BWL_POST_PACKED_STRUCT local_supported_cmd_evt_parms_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct status_change_evt_parms { ++ uint8 status; ++ uint8 amp_status; ++} BWL_POST_PACKED_STRUCT status_change_evt_parms_t; ++ ++/* AMP HCI error codes */ ++#define HCI_SUCCESS 0x00 ++#define HCI_ERR_ILLEGAL_COMMAND 0x01 ++#define HCI_ERR_NO_CONNECTION 0x02 ++#define HCI_ERR_MEMORY_FULL 0x07 ++#define HCI_ERR_CONNECTION_TIMEOUT 0x08 ++#define HCI_ERR_MAX_NUM_OF_CONNECTIONS 0x09 ++#define HCI_ERR_CONNECTION_EXISTS 0x0B ++#define HCI_ERR_CONNECTION_DISALLOWED 0x0C ++#define HCI_ERR_CONNECTION_ACCEPT_TIMEOUT 0x10 ++#define HCI_ERR_UNSUPPORTED_VALUE 0x11 ++#define HCI_ERR_ILLEGAL_PARAMETER_FMT 0x12 ++#define HCI_ERR_CONN_TERM_BY_LOCAL_HOST 0x16 ++#define HCI_ERR_UNSPECIFIED 0x1F ++#define HCI_ERR_UNIT_KEY_USED 0x26 ++#define HCI_ERR_QOS_REJECTED 0x2D ++#define HCI_ERR_PARAM_OUT_OF_RANGE 0x30 ++#define HCI_ERR_NO_SUITABLE_CHANNEL 0x39 ++#define HCI_ERR_CHANNEL_MOVE 0xFF ++ ++/* AMP HCI ACL Data packet format */ ++typedef BWL_PRE_PACKED_STRUCT struct amp_hci_ACL_data { ++ uint16 handle; /* 12-bit connection handle + 2-bit PB and 2-bit BC flags */ ++ uint16 dlen; /* data total length */ ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT amp_hci_ACL_data_t; ++ ++#define HCI_ACL_DATA_PREAMBLE_SIZE OFFSETOF(amp_hci_ACL_data_t, data) ++ ++#define HCI_ACL_DATA_BC_FLAGS (0x0 << 14) ++#define HCI_ACL_DATA_PB_FLAGS (0x3 << 12) ++ ++#define HCI_ACL_DATA_HANDLE(handle) ((handle) & 0x0fff) ++#define HCI_ACL_DATA_FLAGS(handle) ((handle) >> 12) ++ ++/* AMP Activity Report packet formats */ ++typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report { ++ uint8 ScheduleKnown; ++ uint8 NumReports; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT amp_hci_activity_report_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report_triple { ++ uint32 StartTime; ++ uint32 Duration; ++ uint32 Periodicity; ++} BWL_POST_PACKED_STRUCT amp_hci_activity_report_triple_t; ++ ++#define HCI_AR_SCHEDULE_KNOWN 0x01 ++ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _bt_amp_hci_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/eapol.h b/drivers/net/wireless/ap6211/include/proto/eapol.h +new file mode 100755 +index 0000000..8936d16 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/eapol.h +@@ -0,0 +1,193 @@ ++/* ++ * 802.1x EAPOL definitions ++ * ++ * See ++ * IEEE Std 802.1X-2001 ++ * IEEE 802.1X RADIUS Usage Guidelines ++ * ++ * Copyright (C) 2002 Broadcom Corporation ++ * ++ * $Id: eapol.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _eapol_h_ ++#define _eapol_h_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++#include ++ ++/* EAPOL for 802.3/Ethernet */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ struct ether_header eth; /* 802.3/Ethernet header */ ++ unsigned char version; /* EAPOL protocol version */ ++ unsigned char type; /* EAPOL type */ ++ unsigned short length; /* Length of body */ ++ unsigned char body[1]; /* Body (optional) */ ++} BWL_POST_PACKED_STRUCT eapol_header_t; ++ ++#define EAPOL_HEADER_LEN 18 ++ ++typedef struct { ++ unsigned char version; /* EAPOL protocol version */ ++ unsigned char type; /* EAPOL type */ ++ unsigned short length; /* Length of body */ ++} eapol_hdr_t; ++ ++#define EAPOL_HDR_LEN 4 ++ ++/* EAPOL version */ ++#define WPA2_EAPOL_VERSION 2 ++#define WPA_EAPOL_VERSION 1 ++#define LEAP_EAPOL_VERSION 1 ++#define SES_EAPOL_VERSION 1 ++ ++/* EAPOL types */ ++#define EAP_PACKET 0 ++#define EAPOL_START 1 ++#define EAPOL_LOGOFF 2 ++#define EAPOL_KEY 3 ++#define EAPOL_ASF 4 ++ ++/* EAPOL-Key types */ ++#define EAPOL_RC4_KEY 1 ++#define EAPOL_WPA2_KEY 2 /* 802.11i/WPA2 */ ++#define EAPOL_WPA_KEY 254 /* WPA */ ++ ++/* RC4 EAPOL-Key header field sizes */ ++#define EAPOL_KEY_REPLAY_LEN 8 ++#define EAPOL_KEY_IV_LEN 16 ++#define EAPOL_KEY_SIG_LEN 16 ++ ++/* RC4 EAPOL-Key */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ unsigned char type; /* Key Descriptor Type */ ++ unsigned short length; /* Key Length (unaligned) */ ++ unsigned char replay[EAPOL_KEY_REPLAY_LEN]; /* Replay Counter */ ++ unsigned char iv[EAPOL_KEY_IV_LEN]; /* Key IV */ ++ unsigned char index; /* Key Flags & Index */ ++ unsigned char signature[EAPOL_KEY_SIG_LEN]; /* Key Signature */ ++ unsigned char key[1]; /* Key (optional) */ ++} BWL_POST_PACKED_STRUCT eapol_key_header_t; ++ ++#define EAPOL_KEY_HEADER_LEN 44 ++ ++/* RC4 EAPOL-Key flags */ ++#define EAPOL_KEY_FLAGS_MASK 0x80 ++#define EAPOL_KEY_BROADCAST 0 ++#define EAPOL_KEY_UNICAST 0x80 ++ ++/* RC4 EAPOL-Key index */ ++#define EAPOL_KEY_INDEX_MASK 0x7f ++ ++/* WPA/802.11i/WPA2 EAPOL-Key header field sizes */ ++#define EAPOL_WPA_KEY_REPLAY_LEN 8 ++#define EAPOL_WPA_KEY_NONCE_LEN 32 ++#define EAPOL_WPA_KEY_IV_LEN 16 ++#define EAPOL_WPA_KEY_RSC_LEN 8 ++#define EAPOL_WPA_KEY_ID_LEN 8 ++#define EAPOL_WPA_KEY_MIC_LEN 16 ++#define EAPOL_WPA_KEY_DATA_LEN (EAPOL_WPA_MAX_KEY_SIZE + AKW_BLOCK_LEN) ++#define EAPOL_WPA_MAX_KEY_SIZE 32 ++ ++/* WPA EAPOL-Key */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ unsigned char type; /* Key Descriptor Type */ ++ unsigned short key_info; /* Key Information (unaligned) */ ++ unsigned short key_len; /* Key Length (unaligned) */ ++ unsigned char replay[EAPOL_WPA_KEY_REPLAY_LEN]; /* Replay Counter */ ++ unsigned char nonce[EAPOL_WPA_KEY_NONCE_LEN]; /* Nonce */ ++ unsigned char iv[EAPOL_WPA_KEY_IV_LEN]; /* Key IV */ ++ unsigned char rsc[EAPOL_WPA_KEY_RSC_LEN]; /* Key RSC */ ++ unsigned char id[EAPOL_WPA_KEY_ID_LEN]; /* WPA:Key ID, 802.11i/WPA2: Reserved */ ++ unsigned char mic[EAPOL_WPA_KEY_MIC_LEN]; /* Key MIC */ ++ unsigned short data_len; /* Key Data Length */ ++ unsigned char data[EAPOL_WPA_KEY_DATA_LEN]; /* Key data */ ++} BWL_POST_PACKED_STRUCT eapol_wpa_key_header_t; ++ ++#define EAPOL_WPA_KEY_LEN 95 ++ ++/* WPA/802.11i/WPA2 KEY KEY_INFO bits */ ++#define WPA_KEY_DESC_V1 0x01 ++#define WPA_KEY_DESC_V2 0x02 ++#define WPA_KEY_DESC_V3 0x03 ++#define WPA_KEY_PAIRWISE 0x08 ++#define WPA_KEY_INSTALL 0x40 ++#define WPA_KEY_ACK 0x80 ++#define WPA_KEY_MIC 0x100 ++#define WPA_KEY_SECURE 0x200 ++#define WPA_KEY_ERROR 0x400 ++#define WPA_KEY_REQ 0x800 ++ ++#define WPA_KEY_DESC_V2_OR_V3 WPA_KEY_DESC_V2 ++ ++/* WPA-only KEY KEY_INFO bits */ ++#define WPA_KEY_INDEX_0 0x00 ++#define WPA_KEY_INDEX_1 0x10 ++#define WPA_KEY_INDEX_2 0x20 ++#define WPA_KEY_INDEX_3 0x30 ++#define WPA_KEY_INDEX_MASK 0x30 ++#define WPA_KEY_INDEX_SHIFT 0x04 ++ ++/* 802.11i/WPA2-only KEY KEY_INFO bits */ ++#define WPA_KEY_ENCRYPTED_DATA 0x1000 ++ ++/* Key Data encapsulation */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 type; ++ uint8 length; ++ uint8 oui[3]; ++ uint8 subtype; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT eapol_wpa2_encap_data_t; ++ ++#define EAPOL_WPA2_ENCAP_DATA_HDR_LEN 6 ++ ++#define WPA2_KEY_DATA_SUBTYPE_GTK 1 ++#define WPA2_KEY_DATA_SUBTYPE_STAKEY 2 ++#define WPA2_KEY_DATA_SUBTYPE_MAC 3 ++#define WPA2_KEY_DATA_SUBTYPE_PMKID 4 ++#define WPA2_KEY_DATA_SUBTYPE_IGTK 9 ++ ++/* GTK encapsulation */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 flags; ++ uint8 reserved; ++ uint8 gtk[EAPOL_WPA_MAX_KEY_SIZE]; ++} BWL_POST_PACKED_STRUCT eapol_wpa2_key_gtk_encap_t; ++ ++#define EAPOL_WPA2_KEY_GTK_ENCAP_HDR_LEN 2 ++ ++#define WPA2_GTK_INDEX_MASK 0x03 ++#define WPA2_GTK_INDEX_SHIFT 0x00 ++ ++#define WPA2_GTK_TRANSMIT 0x04 ++ ++/* IGTK encapsulation */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint16 key_id; ++ uint8 ipn[6]; ++ uint8 key[EAPOL_WPA_MAX_KEY_SIZE]; ++} BWL_POST_PACKED_STRUCT eapol_wpa2_key_igtk_encap_t; ++ ++#define EAPOL_WPA2_KEY_IGTK_ENCAP_HDR_LEN 8 ++ ++/* STAKey encapsulation */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 reserved[2]; ++ uint8 mac[ETHER_ADDR_LEN]; ++ uint8 stakey[EAPOL_WPA_MAX_KEY_SIZE]; ++} BWL_POST_PACKED_STRUCT eapol_wpa2_key_stakey_encap_t; ++ ++#define WPA2_KEY_DATA_PAD 0xdd ++ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _eapol_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/ethernet.h b/drivers/net/wireless/ap6211/include/proto/ethernet.h +new file mode 100755 +index 0000000..a6ce6e1 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/ethernet.h +@@ -0,0 +1,190 @@ ++/* ++ * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: ethernet.h 309193 2012-01-19 00:03:57Z $ ++ */ ++ ++#ifndef _NET_ETHERNET_H_ /* use native BSD ethernet.h when available */ ++#define _NET_ETHERNET_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include "typedefs.h" ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++/* ++ * The number of bytes in an ethernet (MAC) address. ++ */ ++#define ETHER_ADDR_LEN 6 ++ ++/* ++ * The number of bytes in the type field. ++ */ ++#define ETHER_TYPE_LEN 2 ++ ++/* ++ * The number of bytes in the trailing CRC field. ++ */ ++#define ETHER_CRC_LEN 4 ++ ++/* ++ * The length of the combined header. ++ */ ++#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN) ++ ++/* ++ * The minimum packet length. ++ */ ++#define ETHER_MIN_LEN 64 ++ ++/* ++ * The minimum packet user data length. ++ */ ++#define ETHER_MIN_DATA 46 ++ ++/* ++ * The maximum packet length. ++ */ ++#define ETHER_MAX_LEN 1518 ++ ++/* ++ * The maximum packet user data length. ++ */ ++#define ETHER_MAX_DATA 1500 ++ ++/* ether types */ ++#define ETHER_TYPE_MIN 0x0600 /* Anything less than MIN is a length */ ++#define ETHER_TYPE_IP 0x0800 /* IP */ ++#define ETHER_TYPE_ARP 0x0806 /* ARP */ ++#define ETHER_TYPE_8021Q 0x8100 /* 802.1Q */ ++#define ETHER_TYPE_IPV6 0x86dd /* IPv6 */ ++#define ETHER_TYPE_BRCM 0x886c /* Broadcom Corp. */ ++#define ETHER_TYPE_802_1X 0x888e /* 802.1x */ ++#define ETHER_TYPE_802_1X_PREAUTH 0x88c7 /* 802.1x preauthentication */ ++#define ETHER_TYPE_WAI 0x88b4 /* WAI */ ++#define ETHER_TYPE_89_0D 0x890d /* 89-0d frame for TDLS */ ++ ++#define ETHER_TYPE_IPV6 0x86dd /* IPV6 */ ++ ++/* Broadcom subtype follows ethertype; First 2 bytes are reserved; Next 2 are subtype; */ ++#define ETHER_BRCM_SUBTYPE_LEN 4 /* Broadcom 4 byte subtype */ ++ ++/* ether header */ ++#define ETHER_DEST_OFFSET (0 * ETHER_ADDR_LEN) /* dest address offset */ ++#define ETHER_SRC_OFFSET (1 * ETHER_ADDR_LEN) /* src address offset */ ++#define ETHER_TYPE_OFFSET (2 * ETHER_ADDR_LEN) /* ether type offset */ ++ ++/* ++ * A macro to validate a length with ++ */ ++#define ETHER_IS_VALID_LEN(foo) \ ++ ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) ++ ++#define ETHER_FILL_MCAST_ADDR_FROM_IP(ea, mgrp_ip) { \ ++ ((uint8 *)ea)[0] = 0x01; \ ++ ((uint8 *)ea)[1] = 0x00; \ ++ ((uint8 *)ea)[2] = 0x5e; \ ++ ((uint8 *)ea)[3] = ((mgrp_ip) >> 16) & 0x7f; \ ++ ((uint8 *)ea)[4] = ((mgrp_ip) >> 8) & 0xff; \ ++ ((uint8 *)ea)[5] = ((mgrp_ip) >> 0) & 0xff; \ ++} ++ ++#ifndef __INCif_etherh /* Quick and ugly hack for VxWorks */ ++/* ++ * Structure of a 10Mb/s Ethernet header. ++ */ ++BWL_PRE_PACKED_STRUCT struct ether_header { ++ uint8 ether_dhost[ETHER_ADDR_LEN]; ++ uint8 ether_shost[ETHER_ADDR_LEN]; ++ uint16 ether_type; ++} BWL_POST_PACKED_STRUCT; ++ ++/* ++ * Structure of a 48-bit Ethernet address. ++ */ ++BWL_PRE_PACKED_STRUCT struct ether_addr { ++ uint8 octet[ETHER_ADDR_LEN]; ++} BWL_POST_PACKED_STRUCT; ++#endif /* !__INCif_etherh Quick and ugly hack for VxWorks */ ++ ++/* ++ * Takes a pointer, set, test, clear, toggle locally admininistered ++ * address bit in the 48-bit Ethernet address. ++ */ ++#define ETHER_SET_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] | 2)) ++#define ETHER_IS_LOCALADDR(ea) (((uint8 *)(ea))[0] & 2) ++#define ETHER_CLR_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & 0xfd)) ++#define ETHER_TOGGLE_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] ^ 2)) ++ ++/* Takes a pointer, marks unicast address bit in the MAC address */ ++#define ETHER_SET_UNICAST(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & ~1)) ++ ++/* ++ * Takes a pointer, returns true if a 48-bit multicast address ++ * (including broadcast, since it is all ones) ++ */ ++#define ETHER_ISMULTI(ea) (((const uint8 *)(ea))[0] & 1) ++ ++ ++/* compare two ethernet addresses - assumes the pointers can be referenced as shorts */ ++#define ether_cmp(a, b) (!(((short*)(a))[0] == ((short*)(b))[0]) | \ ++ !(((short*)(a))[1] == ((short*)(b))[1]) | \ ++ !(((short*)(a))[2] == ((short*)(b))[2])) ++ ++/* copy an ethernet address - assumes the pointers can be referenced as shorts */ ++#define ether_copy(s, d) { \ ++ ((short*)(d))[0] = ((const short*)(s))[0]; \ ++ ((short*)(d))[1] = ((const short*)(s))[1]; \ ++ ((short*)(d))[2] = ((const short*)(s))[2]; } ++ ++ ++static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}}; ++static const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}}; ++ ++#define ETHER_ISBCAST(ea) ((((uint8 *)(ea))[0] & \ ++ ((uint8 *)(ea))[1] & \ ++ ((uint8 *)(ea))[2] & \ ++ ((uint8 *)(ea))[3] & \ ++ ((uint8 *)(ea))[4] & \ ++ ((uint8 *)(ea))[5]) == 0xff) ++#define ETHER_ISNULLADDR(ea) ((((uint8 *)(ea))[0] | \ ++ ((uint8 *)(ea))[1] | \ ++ ((uint8 *)(ea))[2] | \ ++ ((uint8 *)(ea))[3] | \ ++ ((uint8 *)(ea))[4] | \ ++ ((uint8 *)(ea))[5]) == 0) ++ ++#define ETHER_MOVE_HDR(d, s) \ ++do { \ ++ struct ether_header t; \ ++ t = *(struct ether_header *)(s); \ ++ *(struct ether_header *)(d) = t; \ ++} while (0) ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _NET_ETHERNET_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/p2p.h b/drivers/net/wireless/ap6211/include/proto/p2p.h +new file mode 100755 +index 0000000..6716e2a +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/p2p.h +@@ -0,0 +1,579 @@ ++/* ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * Fundamental types and constants relating to WFA P2P (aka WiFi Direct) ++ * ++ * $Id: p2p.h 356417 2012-09-12 16:41:24Z $ ++ */ ++ ++#ifndef _P2P_H_ ++#define _P2P_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++#include ++#include ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++/* WiFi P2P OUI values */ ++#define P2P_OUI WFA_OUI /* WiFi P2P OUI */ ++#define P2P_VER WFA_OUI_TYPE_P2P /* P2P version: 9=WiFi P2P v1.0 */ ++ ++#define P2P_IE_ID 0xdd /* P2P IE element ID */ ++ ++/* WiFi P2P IE */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_ie { ++ uint8 id; /* IE ID: 0xDD */ ++ uint8 len; /* IE length */ ++ uint8 OUI[3]; /* WiFi P2P specific OUI: P2P_OUI */ ++ uint8 oui_type; /* Identifies P2P version: P2P_VER */ ++ uint8 subelts[1]; /* variable length subelements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_ie wifi_p2p_ie_t; ++ ++#define P2P_IE_FIXED_LEN 6 ++ ++#define P2P_ATTR_ID_OFF 0 ++#define P2P_ATTR_LEN_OFF 1 ++#define P2P_ATTR_DATA_OFF 3 ++ ++#define P2P_ATTR_ID_LEN 1 /* ID filed length */ ++#define P2P_ATTR_LEN_LEN 2 /* length field length */ ++#define P2P_ATTR_HDR_LEN 3 /* ID + 2-byte length field spec 1.02 */ ++ ++/* P2P IE Subelement IDs from WiFi P2P Technical Spec 1.00 */ ++#define P2P_SEID_STATUS 0 /* Status */ ++#define P2P_SEID_MINOR_RC 1 /* Minor Reason Code */ ++#define P2P_SEID_P2P_INFO 2 /* P2P Capability (capabilities info) */ ++#define P2P_SEID_DEV_ID 3 /* P2P Device ID */ ++#define P2P_SEID_INTENT 4 /* Group Owner Intent */ ++#define P2P_SEID_CFG_TIMEOUT 5 /* Configuration Timeout */ ++#define P2P_SEID_CHANNEL 6 /* Channel */ ++#define P2P_SEID_GRP_BSSID 7 /* P2P Group BSSID */ ++#define P2P_SEID_XT_TIMING 8 /* Extended Listen Timing */ ++#define P2P_SEID_INTINTADDR 9 /* Intended P2P Interface Address */ ++#define P2P_SEID_P2P_MGBTY 10 /* P2P Manageability */ ++#define P2P_SEID_CHAN_LIST 11 /* Channel List */ ++#define P2P_SEID_ABSENCE 12 /* Notice of Absence */ ++#define P2P_SEID_DEV_INFO 13 /* Device Info */ ++#define P2P_SEID_GROUP_INFO 14 /* Group Info */ ++#define P2P_SEID_GROUP_ID 15 /* Group ID */ ++#define P2P_SEID_P2P_IF 16 /* P2P Interface */ ++#define P2P_SEID_OP_CHANNEL 17 /* Operating Channel */ ++#define P2P_SEID_INVITE_FLAGS 18 /* Invitation Flags */ ++#define P2P_SEID_VNDR 221 /* Vendor-specific subelement */ ++ ++#define P2P_SE_VS_ID_SERVICES 0x1b /* BRCM proprietary subel: L2 Services */ ++ ++ ++/* WiFi P2P IE subelement: P2P Capability (capabilities info) */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_info_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_P2P_INFO */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 dev; /* Device Capability Bitmap */ ++ uint8 group; /* Group Capability Bitmap */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_info_se_s wifi_p2p_info_se_t; ++ ++/* P2P Capability subelement's Device Capability Bitmap bit values */ ++#define P2P_CAPSE_DEV_SERVICE_DIS 0x1 /* Service Discovery */ ++#define P2P_CAPSE_DEV_CLIENT_DIS 0x2 /* Client Discoverability */ ++#define P2P_CAPSE_DEV_CONCURRENT 0x4 /* Concurrent Operation */ ++#define P2P_CAPSE_DEV_INFRA_MAN 0x8 /* P2P Infrastructure Managed */ ++#define P2P_CAPSE_DEV_LIMIT 0x10 /* P2P Device Limit */ ++#define P2P_CAPSE_INVITE_PROC 0x20 /* P2P Invitation Procedure */ ++ ++/* P2P Capability subelement's Group Capability Bitmap bit values */ ++#define P2P_CAPSE_GRP_OWNER 0x1 /* P2P Group Owner */ ++#define P2P_CAPSE_PERSIST_GRP 0x2 /* Persistent P2P Group */ ++#define P2P_CAPSE_GRP_LIMIT 0x4 /* P2P Group Limit */ ++#define P2P_CAPSE_GRP_INTRA_BSS 0x8 /* Intra-BSS Distribution */ ++#define P2P_CAPSE_GRP_X_CONNECT 0x10 /* Cross Connection */ ++#define P2P_CAPSE_GRP_PERSISTENT 0x20 /* Persistent Reconnect */ ++#define P2P_CAPSE_GRP_FORMATION 0x40 /* Group Formation */ ++ ++ ++/* WiFi P2P IE subelement: Group Owner Intent */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_intent_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_INTENT */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 intent; /* Intent Value 0...15 (0=legacy 15=master only) */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_intent_se_s wifi_p2p_intent_se_t; ++ ++/* WiFi P2P IE subelement: Configuration Timeout */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_cfg_tmo_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_CFG_TIMEOUT */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 go_tmo; /* GO config timeout in units of 10 ms */ ++ uint8 client_tmo; /* Client config timeout in units of 10 ms */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_cfg_tmo_se_s wifi_p2p_cfg_tmo_se_t; ++ ++/* WiFi P2P IE subelement: Listen Channel */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_listen_channel_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_CHANNEL */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 country[3]; /* Country String */ ++ uint8 op_class; /* Operating Class */ ++ uint8 channel; /* Channel */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_listen_channel_se_s wifi_p2p_listen_channel_se_t; ++ ++/* WiFi P2P IE subelement: P2P Group BSSID */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_bssid_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_GRP_BSSID */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mac[6]; /* P2P group bssid */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_grp_bssid_se_s wifi_p2p_grp_bssid_se_t; ++ ++/* WiFi P2P IE subelement: P2P Group ID */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_id_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_GROUP_ID */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mac[6]; /* P2P device address */ ++ uint8 ssid[1]; /* ssid. device id. variable length */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_grp_id_se_s wifi_p2p_grp_id_se_t; ++ ++/* WiFi P2P IE subelement: P2P Interface */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_intf_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_P2P_IF */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mac[6]; /* P2P device address */ ++ uint8 ifaddrs; /* P2P Interface Address count */ ++ uint8 ifaddr[1][6]; /* P2P Interface Address list */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_intf_se_s wifi_p2p_intf_se_t; ++ ++/* WiFi P2P IE subelement: Status */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_status_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_STATUS */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 status; /* Status Code: P2P_STATSE_* */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_status_se_s wifi_p2p_status_se_t; ++ ++/* Status subelement Status Code definitions */ ++#define P2P_STATSE_SUCCESS 0 ++ /* Success */ ++#define P2P_STATSE_FAIL_INFO_CURR_UNAVAIL 1 ++ /* Failed, information currently unavailable */ ++#define P2P_STATSE_PASSED_UP P2P_STATSE_FAIL_INFO_CURR_UNAVAIL ++ /* Old name for above in P2P spec 1.08 and older */ ++#define P2P_STATSE_FAIL_INCOMPAT_PARAMS 2 ++ /* Failed, incompatible parameters */ ++#define P2P_STATSE_FAIL_LIMIT_REACHED 3 ++ /* Failed, limit reached */ ++#define P2P_STATSE_FAIL_INVALID_PARAMS 4 ++ /* Failed, invalid parameters */ ++#define P2P_STATSE_FAIL_UNABLE_TO_ACCOM 5 ++ /* Failed, unable to accomodate request */ ++#define P2P_STATSE_FAIL_PROTO_ERROR 6 ++ /* Failed, previous protocol error or disruptive behaviour */ ++#define P2P_STATSE_FAIL_NO_COMMON_CHAN 7 ++ /* Failed, no common channels */ ++#define P2P_STATSE_FAIL_UNKNOWN_GROUP 8 ++ /* Failed, unknown P2P Group */ ++#define P2P_STATSE_FAIL_INTENT 9 ++ /* Failed, both peers indicated Intent 15 in GO Negotiation */ ++#define P2P_STATSE_FAIL_INCOMPAT_PROVIS 10 ++ /* Failed, incompatible provisioning method */ ++#define P2P_STATSE_FAIL_USER_REJECT 11 ++ /* Failed, rejected by user */ ++ ++/* WiFi P2P IE attribute: Extended Listen Timing */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_ext_se_s { ++ uint8 eltId; /* ID: P2P_SEID_EXT_TIMING */ ++ uint8 len[2]; /* length not including eltId, len fields */ ++ uint8 avail[2]; /* availibility period */ ++ uint8 interval[2]; /* availibility interval */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_ext_se_s wifi_p2p_ext_se_t; ++ ++#define P2P_EXT_MIN 10 /* minimum 10ms */ ++ ++/* WiFi P2P IE subelement: Intended P2P Interface Address */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_intintad_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_INTINTADDR */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mac[6]; /* intended P2P interface MAC address */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_intintad_se_s wifi_p2p_intintad_se_t; ++ ++/* WiFi P2P IE subelement: Channel */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_channel_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_STATUS */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 band; /* Regulatory Class (band) */ ++ uint8 channel; /* Channel */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_channel_se_s wifi_p2p_channel_se_t; ++ ++ ++/* Channel Entry structure within the Channel List SE */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_entry_s { ++ uint8 band; /* Regulatory Class (band) */ ++ uint8 num_channels; /* # of channels in the channel list */ ++ uint8 channels[WL_NUMCHANNELS]; /* Channel List */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_chanlist_entry_s wifi_p2p_chanlist_entry_t; ++#define WIFI_P2P_CHANLIST_SE_MAX_ENTRIES 2 ++ ++/* WiFi P2P IE subelement: Channel List */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_CHAN_LIST */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 country[3]; /* Country String */ ++ uint8 num_entries; /* # of channel entries */ ++ wifi_p2p_chanlist_entry_t entries[WIFI_P2P_CHANLIST_SE_MAX_ENTRIES]; ++ /* Channel Entry List */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_chanlist_se_s wifi_p2p_chanlist_se_t; ++ ++/* WiFi Primary Device Type structure */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_pri_devtype_s { ++ uint16 cat_id; /* Category ID */ ++ uint8 OUI[3]; /* WFA OUI: 0x0050F2 */ ++ uint8 oui_type; /* WPS_OUI_TYPE */ ++ uint16 sub_cat_id; /* Sub Category ID */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_pri_devtype_s wifi_p2p_pri_devtype_t; ++ ++/* WiFi P2P IE's Device Info subelement */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_devinfo_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_DEVINFO */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mac[6]; /* P2P Device MAC address */ ++ uint16 wps_cfg_meths; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */ ++ uint8 pri_devtype[8]; /* Primary Device Type */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_devinfo_se_s wifi_p2p_devinfo_se_t; ++ ++#define P2P_DEV_TYPE_LEN 8 ++ ++/* WiFi P2P IE's Group Info subelement Client Info Descriptor */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_cid_fixed_s { ++ uint8 len; ++ uint8 devaddr[ETHER_ADDR_LEN]; /* P2P Device Address */ ++ uint8 ifaddr[ETHER_ADDR_LEN]; /* P2P Interface Address */ ++ uint8 devcap; /* Device Capability */ ++ uint8 cfg_meths[2]; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */ ++ uint8 pridt[P2P_DEV_TYPE_LEN]; /* Primary Device Type */ ++ uint8 secdts; /* Number of Secondary Device Types */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_cid_fixed_s wifi_p2p_cid_fixed_t; ++ ++/* WiFi P2P IE's Device ID subelement */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_devid_se_s { ++ uint8 eltId; ++ uint8 len[2]; ++ struct ether_addr addr; /* P2P Device MAC address */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_devid_se_s wifi_p2p_devid_se_t; ++ ++/* WiFi P2P IE subelement: P2P Manageability */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_mgbt_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_P2P_MGBTY */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mg_bitmap; /* manageability bitmap */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_mgbt_se_s wifi_p2p_mgbt_se_t; ++/* mg_bitmap field bit values */ ++#define P2P_MGBTSE_P2PDEVMGMT_FLAG 0x1 /* AP supports Managed P2P Device */ ++ ++/* WiFi P2P IE subelement: Group Info */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_grpinfo_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_GROUP_INFO */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_grpinfo_se_s wifi_p2p_grpinfo_se_t; ++ ++/* WiFi IE subelement: Operating Channel */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_op_channel_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_OP_CHANNEL */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 country[3]; /* Country String */ ++ uint8 op_class; /* Operating Class */ ++ uint8 channel; /* Channel */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_op_channel_se_s wifi_p2p_op_channel_se_t; ++ ++/* WiFi IE subelement: INVITATION FLAGS */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_invite_flags_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_INVITE_FLAGS */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 flags; /* Flags */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_invite_flags_se_s wifi_p2p_invite_flags_se_t; ++ ++/* WiFi P2P Action Frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_action_frame { ++ uint8 category; /* P2P_AF_CATEGORY */ ++ uint8 OUI[3]; /* OUI - P2P_OUI */ ++ uint8 type; /* OUI Type - P2P_VER */ ++ uint8 subtype; /* OUI Subtype - P2P_AF_* */ ++ uint8 dialog_token; /* nonzero, identifies req/resp tranaction */ ++ uint8 elts[1]; /* Variable length information elements. Max size = ++ * ACTION_FRAME_SIZE - sizeof(this structure) - 1 ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_action_frame wifi_p2p_action_frame_t; ++#define P2P_AF_CATEGORY 0x7f ++ ++#define P2P_AF_FIXED_LEN 7 ++ ++/* WiFi P2P Action Frame OUI Subtypes */ ++#define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */ ++#define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */ ++#define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */ ++#define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */ ++ ++ ++/* WiFi P2P Public Action Frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_pub_act_frame { ++ uint8 category; /* P2P_PUB_AF_CATEGORY */ ++ uint8 action; /* P2P_PUB_AF_ACTION */ ++ uint8 oui[3]; /* P2P_OUI */ ++ uint8 oui_type; /* OUI type - P2P_VER */ ++ uint8 subtype; /* OUI subtype - P2P_TYPE_* */ ++ uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ ++ uint8 elts[1]; /* Variable length information elements. Max size = ++ * ACTION_FRAME_SIZE - sizeof(this structure) - 1 ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_pub_act_frame wifi_p2p_pub_act_frame_t; ++#define P2P_PUB_AF_FIXED_LEN 8 ++#define P2P_PUB_AF_CATEGORY 0x04 ++#define P2P_PUB_AF_ACTION 0x09 ++ ++/* WiFi P2P Public Action Frame OUI Subtypes */ ++#define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */ ++#define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */ ++#define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */ ++#define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */ ++#define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */ ++#define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */ ++#define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */ ++#define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */ ++#define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Response */ ++#define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */ ++ ++/* TODO: Stop using these obsolete aliases for P2P_PAF_GON_* */ ++#define P2P_TYPE_MNREQ P2P_PAF_GON_REQ ++#define P2P_TYPE_MNRSP P2P_PAF_GON_RSP ++#define P2P_TYPE_MNCONF P2P_PAF_GON_CONF ++ ++/* WiFi P2P IE subelement: Notice of Absence */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_desc { ++ uint8 cnt_type; /* Count/Type */ ++ uint32 duration; /* Duration */ ++ uint32 interval; /* Interval */ ++ uint32 start; /* Start Time */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_noa_desc wifi_p2p_noa_desc_t; ++ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_se { ++ uint8 eltId; /* Subelement ID */ ++ uint8 len[2]; /* Length */ ++ uint8 index; /* Index */ ++ uint8 ops_ctw_parms; /* CTWindow and OppPS Parameters */ ++ wifi_p2p_noa_desc_t desc[1]; /* Notice of Absence Descriptor(s) */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_noa_se wifi_p2p_noa_se_t; ++ ++#define P2P_NOA_SE_FIXED_LEN 5 ++ ++/* cnt_type field values */ ++#define P2P_NOA_DESC_CNT_RESERVED 0 /* reserved and should not be used */ ++#define P2P_NOA_DESC_CNT_REPEAT 255 /* continuous schedule */ ++#define P2P_NOA_DESC_TYPE_PREFERRED 1 /* preferred values */ ++#define P2P_NOA_DESC_TYPE_ACCEPTABLE 2 /* acceptable limits */ ++ ++/* ctw_ops_parms field values */ ++#define P2P_NOA_CTW_MASK 0x7f ++#define P2P_NOA_OPS_MASK 0x80 ++#define P2P_NOA_OPS_SHIFT 7 ++ ++#define P2P_CTW_MIN 10 /* minimum 10TU */ ++ ++/* ++ * P2P Service Discovery related ++ */ ++#define P2PSD_ACTION_CATEGORY 0x04 ++ /* Public action frame */ ++#define P2PSD_ACTION_ID_GAS_IREQ 0x0a ++ /* Action value for GAS Initial Request AF */ ++#define P2PSD_ACTION_ID_GAS_IRESP 0x0b ++ /* Action value for GAS Initial Response AF */ ++#define P2PSD_ACTION_ID_GAS_CREQ 0x0c ++ /* Action value for GAS Comback Request AF */ ++#define P2PSD_ACTION_ID_GAS_CRESP 0x0d ++ /* Action value for GAS Comback Response AF */ ++#define P2PSD_AD_EID 0x6c ++ /* Advertisement Protocol IE ID */ ++#define P2PSD_ADP_TUPLE_QLMT_PAMEBI 0x00 ++ /* Query Response Length Limit 7 bits plus PAME-BI 1 bit */ ++#define P2PSD_ADP_PROTO_ID 0x00 ++ /* Advertisement Protocol ID. Always 0 for P2P SD */ ++#define P2PSD_GAS_OUI P2P_OUI ++ /* WFA OUI */ ++#define P2PSD_GAS_OUI_SUBTYPE P2P_VER ++ /* OUI Subtype for GAS IE */ ++#define P2PSD_GAS_NQP_INFOID 0xDDDD ++ /* NQP Query Info ID: 56797 */ ++#define P2PSD_GAS_COMEBACKDEALY 0x00 ++ /* Not used in the Native GAS protocol */ ++ ++/* Service Protocol Type */ ++typedef enum p2psd_svc_protype { ++ SVC_RPOTYPE_ALL = 0, ++ SVC_RPOTYPE_BONJOUR = 1, ++ SVC_RPOTYPE_UPNP = 2, ++ SVC_RPOTYPE_WSD = 3, ++ SVC_RPOTYPE_VENDOR = 255 ++} p2psd_svc_protype_t; ++ ++/* Service Discovery response status code */ ++typedef enum { ++ P2PSD_RESP_STATUS_SUCCESS = 0, ++ P2PSD_RESP_STATUS_PROTYPE_NA = 1, ++ P2PSD_RESP_STATUS_DATA_NA = 2, ++ P2PSD_RESP_STATUS_BAD_REQUEST = 3 ++} p2psd_resp_status_t; ++ ++/* Advertisement Protocol IE tuple field */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_tpl { ++ uint8 llm_pamebi; /* Query Response Length Limit bit 0-6, set to 0 plus ++ * Pre-Associated Message Exchange BSSID Independent bit 7, set to 0 ++ */ ++ uint8 adp_id; /* Advertisement Protocol ID: 0 for NQP Native Query Protocol */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_adp_tpl wifi_p2psd_adp_tpl_t; ++ ++/* Advertisement Protocol IE */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_ie { ++ uint8 id; /* IE ID: 0x6c - 108 */ ++ uint8 len; /* IE length */ ++ wifi_p2psd_adp_tpl_t adp_tpl; /* Advertisement Protocol Tuple field. Only one ++ * tuple is defined for P2P Service Discovery ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_adp_ie wifi_p2psd_adp_ie_t; ++ ++/* NQP Vendor-specific Content */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_nqp_query_vsc { ++ uint8 oui_subtype; /* OUI Subtype: 0x09 */ ++ uint16 svc_updi; /* Service Update Indicator */ ++ uint8 svc_tlvs[1]; /* wifi_p2psd_qreq_tlv_t type for service request, ++ * wifi_p2psd_qresp_tlv_t type for service response ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_nqp_query_vsc wifi_p2psd_nqp_query_vsc_t; ++ ++/* Service Request TLV */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_tlv { ++ uint16 len; /* Length: 5 plus size of Query Data */ ++ uint8 svc_prot; /* Service Protocol Type */ ++ uint8 svc_tscid; /* Service Transaction ID */ ++ uint8 query_data[1]; /* Query Data, passed in from above Layer 2 */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_qreq_tlv wifi_p2psd_qreq_tlv_t; ++ ++/* Query Request Frame, defined in generic format, instead of NQP specific */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_frame { ++ uint16 info_id; /* Info ID: 0xDDDD */ ++ uint16 len; /* Length of service request TLV, 5 plus the size of request data */ ++ uint8 oui[3]; /* WFA OUI: 0x0050F2 */ ++ uint8 qreq_vsc[1]; /* Vendor-specific Content: wifi_p2psd_nqp_query_vsc_t type for NQP */ ++ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_qreq_frame wifi_p2psd_qreq_frame_t; ++ ++/* GAS Initial Request AF body, "elts" in wifi_p2p_pub_act_frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_ireq_frame { ++ wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ ++ uint16 qreq_len; /* Query Request Length */ ++ uint8 qreq_frm[1]; /* Query Request Frame wifi_p2psd_qreq_frame_t */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_gas_ireq_frame wifi_p2psd_gas_ireq_frame_t; ++ ++/* Service Response TLV */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_tlv { ++ uint16 len; /* Length: 5 plus size of Query Data */ ++ uint8 svc_prot; /* Service Protocol Type */ ++ uint8 svc_tscid; /* Service Transaction ID */ ++ uint8 status; /* Value defined in Table 57 of P2P spec. */ ++ uint8 query_data[1]; /* Response Data, passed in from above Layer 2 */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_qresp_tlv wifi_p2psd_qresp_tlv_t; ++ ++/* Query Response Frame, defined in generic format, instead of NQP specific */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_frame { ++ uint16 info_id; /* Info ID: 0xDDDD */ ++ uint16 len; /* Lenth of service response TLV, 6 plus the size of resp data */ ++ uint8 oui[3]; /* WFA OUI: 0x0050F2 */ ++ uint8 qresp_vsc[1]; /* Vendor-specific Content: wifi_p2psd_qresp_tlv_t type for NQP */ ++ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_qresp_frame wifi_p2psd_qresp_frame_t; ++ ++/* GAS Initial Response AF body, "elts" in wifi_p2p_pub_act_frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_iresp_frame { ++ uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ ++ uint16 cb_delay; /* GAS Comeback Delay */ ++ wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ ++ uint16 qresp_len; /* Query Response Length */ ++ uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_gas_iresp_frame wifi_p2psd_gas_iresp_frame_t; ++ ++/* GAS Comeback Response AF body, "elts" in wifi_p2p_pub_act_frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_cresp_frame { ++ uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ ++ uint8 fragment_id; /* Fragmentation ID */ ++ uint16 cb_delay; /* GAS Comeback Delay */ ++ wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ ++ uint16 qresp_len; /* Query Response Length */ ++ uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_gas_cresp_frame wifi_p2psd_gas_cresp_frame_t; ++ ++/* Wi-Fi GAS Public Action Frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_pub_act_frame { ++ uint8 category; /* 0x04 Public Action Frame */ ++ uint8 action; /* 0x6c Advertisement Protocol */ ++ uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ ++ uint8 query_data[1]; /* Query Data. wifi_p2psd_gas_ireq_frame_t ++ * or wifi_p2psd_gas_iresp_frame_t format ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_gas_pub_act_frame wifi_p2psd_gas_pub_act_frame_t; ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _P2P_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/sdspi.h b/drivers/net/wireless/ap6211/include/proto/sdspi.h +new file mode 100755 +index 0000000..a4900ed +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/sdspi.h +@@ -0,0 +1,75 @@ ++/* ++ * SD-SPI Protocol Standard ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sdspi.h 241182 2011-02-17 21:50:03Z $ ++ */ ++#ifndef _SD_SPI_H ++#define _SD_SPI_H ++ ++#define SPI_START_M BITFIELD_MASK(1) /* Bit [31] - Start Bit */ ++#define SPI_START_S 31 ++#define SPI_DIR_M BITFIELD_MASK(1) /* Bit [30] - Direction */ ++#define SPI_DIR_S 30 ++#define SPI_CMD_INDEX_M BITFIELD_MASK(6) /* Bits [29:24] - Command number */ ++#define SPI_CMD_INDEX_S 24 ++#define SPI_RW_M BITFIELD_MASK(1) /* Bit [23] - Read=0, Write=1 */ ++#define SPI_RW_S 23 ++#define SPI_FUNC_M BITFIELD_MASK(3) /* Bits [22:20] - Function Number */ ++#define SPI_FUNC_S 20 ++#define SPI_RAW_M BITFIELD_MASK(1) /* Bit [19] - Read After Wr */ ++#define SPI_RAW_S 19 ++#define SPI_STUFF_M BITFIELD_MASK(1) /* Bit [18] - Stuff bit */ ++#define SPI_STUFF_S 18 ++#define SPI_BLKMODE_M BITFIELD_MASK(1) /* Bit [19] - Blockmode 1=blk */ ++#define SPI_BLKMODE_S 19 ++#define SPI_OPCODE_M BITFIELD_MASK(1) /* Bit [18] - OP Code */ ++#define SPI_OPCODE_S 18 ++#define SPI_ADDR_M BITFIELD_MASK(17) /* Bits [17:1] - Address */ ++#define SPI_ADDR_S 1 ++#define SPI_STUFF0_M BITFIELD_MASK(1) /* Bit [0] - Stuff bit */ ++#define SPI_STUFF0_S 0 ++ ++#define SPI_RSP_START_M BITFIELD_MASK(1) /* Bit [7] - Start Bit (always 0) */ ++#define SPI_RSP_START_S 7 ++#define SPI_RSP_PARAM_ERR_M BITFIELD_MASK(1) /* Bit [6] - Parameter Error */ ++#define SPI_RSP_PARAM_ERR_S 6 ++#define SPI_RSP_RFU5_M BITFIELD_MASK(1) /* Bit [5] - RFU (Always 0) */ ++#define SPI_RSP_RFU5_S 5 ++#define SPI_RSP_FUNC_ERR_M BITFIELD_MASK(1) /* Bit [4] - Function number error */ ++#define SPI_RSP_FUNC_ERR_S 4 ++#define SPI_RSP_CRC_ERR_M BITFIELD_MASK(1) /* Bit [3] - COM CRC Error */ ++#define SPI_RSP_CRC_ERR_S 3 ++#define SPI_RSP_ILL_CMD_M BITFIELD_MASK(1) /* Bit [2] - Illegal Command error */ ++#define SPI_RSP_ILL_CMD_S 2 ++#define SPI_RSP_RFU1_M BITFIELD_MASK(1) /* Bit [1] - RFU (Always 0) */ ++#define SPI_RSP_RFU1_S 1 ++#define SPI_RSP_IDLE_M BITFIELD_MASK(1) /* Bit [0] - In idle state */ ++#define SPI_RSP_IDLE_S 0 ++ ++/* SD-SPI Protocol Definitions */ ++#define SDSPI_COMMAND_LEN 6 /* Number of bytes in an SD command */ ++#define SDSPI_START_BLOCK 0xFE /* SD Start Block Token */ ++#define SDSPI_IDLE_PAD 0xFF /* SD-SPI idle value for MOSI */ ++#define SDSPI_START_BIT_MASK 0x80 ++ ++#endif /* _SD_SPI_H */ +diff --git a/drivers/net/wireless/ap6211/include/proto/vlan.h b/drivers/net/wireless/ap6211/include/proto/vlan.h +new file mode 100755 +index 0000000..88502bf +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/vlan.h +@@ -0,0 +1,69 @@ ++/* ++ * 802.1Q VLAN protocol definitions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: vlan.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _vlan_h_ ++#define _vlan_h_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++#define VLAN_VID_MASK 0xfff /* low 12 bits are vlan id */ ++#define VLAN_CFI_SHIFT 12 /* canonical format indicator bit */ ++#define VLAN_PRI_SHIFT 13 /* user priority */ ++ ++#define VLAN_PRI_MASK 7 /* 3 bits of priority */ ++ ++#define VLAN_TAG_LEN 4 ++#define VLAN_TAG_OFFSET (2 * ETHER_ADDR_LEN) /* offset in Ethernet II packet only */ ++ ++#define VLAN_TPID 0x8100 /* VLAN ethertype/Tag Protocol ID */ ++ ++struct ethervlan_header { ++ uint8 ether_dhost[ETHER_ADDR_LEN]; ++ uint8 ether_shost[ETHER_ADDR_LEN]; ++ uint16 vlan_type; /* 0x8100 */ ++ uint16 vlan_tag; /* priority, cfi and vid */ ++ uint16 ether_type; ++}; ++ ++#define ETHERVLAN_HDR_LEN (ETHER_HDR_LEN + VLAN_TAG_LEN) ++ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#define ETHERVLAN_MOVE_HDR(d, s) \ ++do { \ ++ struct ethervlan_header t; \ ++ t = *(struct ethervlan_header *)(s); \ ++ *(struct ethervlan_header *)(d) = t; \ ++} while (0) ++ ++#endif /* _vlan_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/proto/wpa.h b/drivers/net/wireless/ap6211/include/proto/wpa.h +new file mode 100755 +index 0000000..23ab8d6 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/proto/wpa.h +@@ -0,0 +1,206 @@ ++/* ++ * Fundamental types and constants relating to WPA ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wpa.h 261155 2011-05-23 23:51:32Z $ ++ */ ++ ++#ifndef _proto_wpa_h_ ++#define _proto_wpa_h_ ++ ++#include ++#include ++ ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++/* Reason Codes */ ++ ++/* 13 through 23 taken from IEEE Std 802.11i-2004 */ ++#define DOT11_RC_INVALID_WPA_IE 13 /* Invalid info. element */ ++#define DOT11_RC_MIC_FAILURE 14 /* Michael failure */ ++#define DOT11_RC_4WH_TIMEOUT 15 /* 4-way handshake timeout */ ++#define DOT11_RC_GTK_UPDATE_TIMEOUT 16 /* Group key update timeout */ ++#define DOT11_RC_WPA_IE_MISMATCH 17 /* WPA IE in 4-way handshake differs from ++ * (re-)assoc. request/probe response ++ */ ++#define DOT11_RC_INVALID_MC_CIPHER 18 /* Invalid multicast cipher */ ++#define DOT11_RC_INVALID_UC_CIPHER 19 /* Invalid unicast cipher */ ++#define DOT11_RC_INVALID_AKMP 20 /* Invalid authenticated key management protocol */ ++#define DOT11_RC_BAD_WPA_VERSION 21 /* Unsupported WPA version */ ++#define DOT11_RC_INVALID_WPA_CAP 22 /* Invalid WPA IE capabilities */ ++#define DOT11_RC_8021X_AUTH_FAIL 23 /* 802.1X authentication failure */ ++ ++#define WPA2_PMKID_LEN 16 ++ ++/* WPA IE fixed portion */ ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ uint8 tag; /* TAG */ ++ uint8 length; /* TAG length */ ++ uint8 oui[3]; /* IE OUI */ ++ uint8 oui_type; /* OUI type */ ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 low; ++ uint8 high; ++ } BWL_POST_PACKED_STRUCT version; /* IE version */ ++} BWL_POST_PACKED_STRUCT wpa_ie_fixed_t; ++#define WPA_IE_OUITYPE_LEN 4 ++#define WPA_IE_FIXED_LEN 8 ++#define WPA_IE_TAG_FIXED_LEN 6 ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 tag; /* TAG */ ++ uint8 length; /* TAG length */ ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 low; ++ uint8 high; ++ } BWL_POST_PACKED_STRUCT version; /* IE version */ ++} BWL_POST_PACKED_STRUCT wpa_rsn_ie_fixed_t; ++#define WPA_RSN_IE_FIXED_LEN 4 ++#define WPA_RSN_IE_TAG_FIXED_LEN 2 ++typedef uint8 wpa_pmkid_t[WPA2_PMKID_LEN]; ++ ++/* WPA suite/multicast suite */ ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ uint8 oui[3]; ++ uint8 type; ++} BWL_POST_PACKED_STRUCT wpa_suite_t, wpa_suite_mcast_t; ++#define WPA_SUITE_LEN 4 ++ ++/* WPA unicast suite list/key management suite list */ ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 low; ++ uint8 high; ++ } BWL_POST_PACKED_STRUCT count; ++ wpa_suite_t list[1]; ++} BWL_POST_PACKED_STRUCT wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t; ++#define WPA_IE_SUITE_COUNT_LEN 2 ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 low; ++ uint8 high; ++ } BWL_POST_PACKED_STRUCT count; ++ wpa_pmkid_t list[1]; ++} BWL_POST_PACKED_STRUCT wpa_pmkid_list_t; ++ ++/* WPA cipher suites */ ++#define WPA_CIPHER_NONE 0 /* None */ ++#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */ ++#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */ ++#define WPA_CIPHER_AES_OCB 3 /* AES (OCB) */ ++#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */ ++#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */ ++#define WPA_CIPHER_BIP 6 /* WEP (104-bit) */ ++#define WPA_CIPHER_TPK 7 /* Group addressed traffic not allowed */ ++#ifdef BCMWAPI_WPI ++#define WAPI_CIPHER_NONE WPA_CIPHER_NONE ++#define WAPI_CIPHER_SMS4 11 ++ ++#define WAPI_CSE_WPI_SMS4 1 ++#endif /* BCMWAPI_WPI */ ++ ++ ++#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \ ++ (cipher) == WPA_CIPHER_WEP_40 || \ ++ (cipher) == WPA_CIPHER_WEP_104 || \ ++ (cipher) == WPA_CIPHER_TKIP || \ ++ (cipher) == WPA_CIPHER_AES_OCB || \ ++ (cipher) == WPA_CIPHER_AES_CCM || \ ++ (cipher) == WPA_CIPHER_TPK) ++ ++#ifdef BCMWAPI_WAI ++#define IS_WAPI_CIPHER(cipher) ((cipher) == WAPI_CIPHER_NONE || \ ++ (cipher) == WAPI_CSE_WPI_SMS4) ++ ++/* convert WAPI_CSE_WPI_XXX to WAPI_CIPHER_XXX */ ++#define WAPI_CSE_WPI_2_CIPHER(cse) ((cse) == WAPI_CSE_WPI_SMS4 ? \ ++ WAPI_CIPHER_SMS4 : WAPI_CIPHER_NONE) ++ ++#define WAPI_CIPHER_2_CSE_WPI(cipher) ((cipher) == WAPI_CIPHER_SMS4 ? \ ++ WAPI_CSE_WPI_SMS4 : WAPI_CIPHER_NONE) ++#endif /* BCMWAPI_WAI */ ++ ++ ++/* WPA TKIP countermeasures parameters */ ++#define WPA_TKIP_CM_DETECT 60 /* multiple MIC failure window (seconds) */ ++#define WPA_TKIP_CM_BLOCK 60 /* countermeasures active window (seconds) */ ++ ++/* RSN IE defines */ ++#define RSN_CAP_LEN 2 /* Length of RSN capabilities field (2 octets) */ ++ ++/* RSN Capabilities defined in 802.11i */ ++#define RSN_CAP_PREAUTH 0x0001 ++#define RSN_CAP_NOPAIRWISE 0x0002 ++#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C ++#define RSN_CAP_PTK_REPLAY_CNTR_SHIFT 2 ++#define RSN_CAP_GTK_REPLAY_CNTR_MASK 0x0030 ++#define RSN_CAP_GTK_REPLAY_CNTR_SHIFT 4 ++#define RSN_CAP_1_REPLAY_CNTR 0 ++#define RSN_CAP_2_REPLAY_CNTRS 1 ++#define RSN_CAP_4_REPLAY_CNTRS 2 ++#define RSN_CAP_16_REPLAY_CNTRS 3 ++#ifdef MFP ++#define RSN_CAP_MFPR 0x0040 ++#define RSN_CAP_MFPC 0x0080 ++#endif ++ ++/* WPA capabilities defined in 802.11i */ ++#define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS ++#define WPA_CAP_16_REPLAY_CNTRS RSN_CAP_16_REPLAY_CNTRS ++#define WPA_CAP_REPLAY_CNTR_SHIFT RSN_CAP_PTK_REPLAY_CNTR_SHIFT ++#define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK ++ ++/* WPA capabilities defined in 802.11zD9.0 */ ++#define WPA_CAP_PEER_KEY_ENABLE (0x1 << 1) /* bit 9 */ ++ ++/* WPA Specific defines */ ++#define WPA_CAP_LEN RSN_CAP_LEN /* Length of RSN capabilities in RSN IE (2 octets) */ ++#define WPA_PMKID_CNT_LEN 2 /* Length of RSN PMKID count (2 octests) */ ++ ++#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH ++ ++#ifdef BCMWAPI_WAI ++#define WAPI_CAP_PREAUTH RSN_CAP_PREAUTH ++ ++/* Other WAI definition */ ++#define WAPI_WAI_REQUEST 0x00F1 ++#define WAPI_UNICAST_REKEY 0x00F2 ++#define WAPI_STA_AGING 0x00F3 ++#define WAPI_MUTIL_REKEY 0x00F4 ++#define WAPI_STA_STATS 0x00F5 ++ ++#define WAPI_USK_REKEY_COUNT 0x4000000 /* 0xA00000 */ ++#define WAPI_MSK_REKEY_COUNT 0x4000000 /* 0xA00000 */ ++#endif /* BCMWAPI_WAI */ ++#define WPA2_PMKID_COUNT_LEN 2 ++ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _proto_wpa_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/sbchipc.h b/drivers/net/wireless/ap6211/include/sbchipc.h +new file mode 100755 +index 0000000..c694291 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sbchipc.h +@@ -0,0 +1,2405 @@ ++/* ++ * SiliconBackplane Chipcommon core hardware definitions. ++ * ++ * The chipcommon core provides chip identification, SB control, ++ * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer, ++ * GPIO interface, extbus, and support for serial and parallel flashes. ++ * ++ * $Id: sbchipc.h 347614 2012-07-27 10:24:51Z $ ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ */ ++ ++#ifndef _SBCHIPC_H ++#define _SBCHIPC_H ++ ++#ifndef _LANGUAGE_ASSEMBLY ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif /* PAD */ ++ ++typedef struct eci_prerev35 { ++ uint32 eci_output; ++ uint32 eci_control; ++ uint32 eci_inputlo; ++ uint32 eci_inputmi; ++ uint32 eci_inputhi; ++ uint32 eci_inputintpolaritylo; ++ uint32 eci_inputintpolaritymi; ++ uint32 eci_inputintpolarityhi; ++ uint32 eci_intmasklo; ++ uint32 eci_intmaskmi; ++ uint32 eci_intmaskhi; ++ uint32 eci_eventlo; ++ uint32 eci_eventmi; ++ uint32 eci_eventhi; ++ uint32 eci_eventmasklo; ++ uint32 eci_eventmaskmi; ++ uint32 eci_eventmaskhi; ++ uint32 PAD[3]; ++} eci_prerev35_t; ++ ++typedef struct eci_rev35 { ++ uint32 eci_outputlo; ++ uint32 eci_outputhi; ++ uint32 eci_controllo; ++ uint32 eci_controlhi; ++ uint32 eci_inputlo; ++ uint32 eci_inputhi; ++ uint32 eci_inputintpolaritylo; ++ uint32 eci_inputintpolarityhi; ++ uint32 eci_intmasklo; ++ uint32 eci_intmaskhi; ++ uint32 eci_eventlo; ++ uint32 eci_eventhi; ++ uint32 eci_eventmasklo; ++ uint32 eci_eventmaskhi; ++ uint32 eci_auxtx; ++ uint32 eci_auxrx; ++ uint32 eci_datatag; ++ uint32 eci_uartescvalue; ++ uint32 eci_autobaudctr; ++ uint32 eci_uartfifolevel; ++} eci_rev35_t; ++ ++typedef struct flash_config { ++ uint32 PAD[19]; ++ /* Flash struct configuration registers (0x18c) for BCM4706 (corerev = 31) */ ++ uint32 flashstrconfig; ++} flash_config_t; ++ ++typedef volatile struct { ++ uint32 chipid; /* 0x0 */ ++ uint32 capabilities; ++ uint32 corecontrol; /* corerev >= 1 */ ++ uint32 bist; ++ ++ /* OTP */ ++ uint32 otpstatus; /* 0x10, corerev >= 10 */ ++ uint32 otpcontrol; ++ uint32 otpprog; ++ uint32 otplayout; /* corerev >= 23 */ ++ ++ /* Interrupt control */ ++ uint32 intstatus; /* 0x20 */ ++ uint32 intmask; ++ ++ /* Chip specific regs */ ++ uint32 chipcontrol; /* 0x28, rev >= 11 */ ++ uint32 chipstatus; /* 0x2c, rev >= 11 */ ++ ++ /* Jtag Master */ ++ uint32 jtagcmd; /* 0x30, rev >= 10 */ ++ uint32 jtagir; ++ uint32 jtagdr; ++ uint32 jtagctrl; ++ ++ /* serial flash interface registers */ ++ uint32 flashcontrol; /* 0x40 */ ++ uint32 flashaddress; ++ uint32 flashdata; ++ uint32 otplayoutextension; /* rev >= 35 */ ++ ++ /* Silicon backplane configuration broadcast control */ ++ uint32 broadcastaddress; /* 0x50 */ ++ uint32 broadcastdata; ++ ++ /* gpio - cleared only by power-on-reset */ ++ uint32 gpiopullup; /* 0x58, corerev >= 20 */ ++ uint32 gpiopulldown; /* 0x5c, corerev >= 20 */ ++ uint32 gpioin; /* 0x60 */ ++ uint32 gpioout; /* 0x64 */ ++ uint32 gpioouten; /* 0x68 */ ++ uint32 gpiocontrol; /* 0x6C */ ++ uint32 gpiointpolarity; /* 0x70 */ ++ uint32 gpiointmask; /* 0x74 */ ++ ++ /* GPIO events corerev >= 11 */ ++ uint32 gpioevent; ++ uint32 gpioeventintmask; ++ ++ /* Watchdog timer */ ++ uint32 watchdog; /* 0x80 */ ++ ++ /* GPIO events corerev >= 11 */ ++ uint32 gpioeventintpolarity; ++ ++ /* GPIO based LED powersave registers corerev >= 16 */ ++ uint32 gpiotimerval; /* 0x88 */ ++ uint32 gpiotimeroutmask; ++ ++ /* clock control */ ++ uint32 clockcontrol_n; /* 0x90 */ ++ uint32 clockcontrol_sb; /* aka m0 */ ++ uint32 clockcontrol_pci; /* aka m1 */ ++ uint32 clockcontrol_m2; /* mii/uart/mipsref */ ++ uint32 clockcontrol_m3; /* cpu */ ++ uint32 clkdiv; /* corerev >= 3 */ ++ uint32 gpiodebugsel; /* corerev >= 28 */ ++ uint32 capabilities_ext; /* 0xac */ ++ ++ /* pll delay registers (corerev >= 4) */ ++ uint32 pll_on_delay; /* 0xb0 */ ++ uint32 fref_sel_delay; ++ uint32 slow_clk_ctl; /* 5 < corerev < 10 */ ++ uint32 PAD; ++ ++ /* Instaclock registers (corerev >= 10) */ ++ uint32 system_clk_ctl; /* 0xc0 */ ++ uint32 clkstatestretch; ++ uint32 PAD[2]; ++ ++ /* Indirect backplane access (corerev >= 22) */ ++ uint32 bp_addrlow; /* 0xd0 */ ++ uint32 bp_addrhigh; ++ uint32 bp_data; ++ uint32 PAD; ++ uint32 bp_indaccess; ++ /* SPI registers, corerev >= 37 */ ++ uint32 gsioctrl; ++ uint32 gsioaddress; ++ uint32 gsiodata; ++ ++ /* More clock dividers (corerev >= 32) */ ++ uint32 clkdiv2; ++ /* FAB ID (corerev >= 40) */ ++ uint32 otpcontrol1; ++ uint32 fabid; /* 0xf8 */ ++ ++ /* In AI chips, pointer to erom */ ++ uint32 eromptr; /* 0xfc */ ++ ++ /* ExtBus control registers (corerev >= 3) */ ++ uint32 pcmcia_config; /* 0x100 */ ++ uint32 pcmcia_memwait; ++ uint32 pcmcia_attrwait; ++ uint32 pcmcia_iowait; ++ uint32 ide_config; ++ uint32 ide_memwait; ++ uint32 ide_attrwait; ++ uint32 ide_iowait; ++ uint32 prog_config; ++ uint32 prog_waitcount; ++ uint32 flash_config; ++ uint32 flash_waitcount; ++ uint32 SECI_config; /* 0x130 SECI configuration */ ++ uint32 SECI_status; ++ uint32 SECI_statusmask; ++ uint32 SECI_rxnibchanged; ++ ++ uint32 PAD[20]; ++ ++ /* SROM interface (corerev >= 32) */ ++ uint32 sromcontrol; /* 0x190 */ ++ uint32 sromaddress; ++ uint32 sromdata; ++ uint32 PAD[1]; /* 0x19C */ ++ /* NAND flash registers for BCM4706 (corerev = 31) */ ++ uint32 nflashctrl; /* 0x1a0 */ ++ uint32 nflashconf; ++ uint32 nflashcoladdr; ++ uint32 nflashrowaddr; ++ uint32 nflashdata; ++ uint32 nflashwaitcnt0; /* 0x1b4 */ ++ uint32 PAD[2]; ++ ++ uint32 seci_uart_data; /* 0x1C0 */ ++ uint32 seci_uart_bauddiv; ++ uint32 seci_uart_fcr; ++ uint32 seci_uart_lcr; ++ uint32 seci_uart_mcr; ++ uint32 seci_uart_lsr; ++ uint32 seci_uart_msr; ++ uint32 seci_uart_baudadj; ++ /* Clock control and hardware workarounds (corerev >= 20) */ ++ uint32 clk_ctl_st; /* 0x1e0 */ ++ uint32 hw_war; ++ uint32 PAD[70]; ++ ++ /* UARTs */ ++ uint8 uart0data; /* 0x300 */ ++ uint8 uart0imr; ++ uint8 uart0fcr; ++ uint8 uart0lcr; ++ uint8 uart0mcr; ++ uint8 uart0lsr; ++ uint8 uart0msr; ++ uint8 uart0scratch; ++ uint8 PAD[248]; /* corerev >= 1 */ ++ ++ uint8 uart1data; /* 0x400 */ ++ uint8 uart1imr; ++ uint8 uart1fcr; ++ uint8 uart1lcr; ++ uint8 uart1mcr; ++ uint8 uart1lsr; ++ uint8 uart1msr; ++ uint8 uart1scratch; ++ uint32 PAD[126]; ++ ++ /* PMU registers (corerev >= 20) */ ++ /* Note: all timers driven by ILP clock are updated asynchronously to HT/ALP. ++ * The CPU must read them twice, compare, and retry if different. ++ */ ++ uint32 pmucontrol; /* 0x600 */ ++ uint32 pmucapabilities; ++ uint32 pmustatus; ++ uint32 res_state; ++ uint32 res_pending; ++ uint32 pmutimer; ++ uint32 min_res_mask; ++ uint32 max_res_mask; ++ uint32 res_table_sel; ++ uint32 res_dep_mask; ++ uint32 res_updn_timer; ++ uint32 res_timer; ++ uint32 clkstretch; ++ uint32 pmuwatchdog; ++ uint32 gpiosel; /* 0x638, rev >= 1 */ ++ uint32 gpioenable; /* 0x63c, rev >= 1 */ ++ uint32 res_req_timer_sel; ++ uint32 res_req_timer; ++ uint32 res_req_mask; ++ uint32 PAD; ++ uint32 chipcontrol_addr; /* 0x650 */ ++ uint32 chipcontrol_data; /* 0x654 */ ++ uint32 regcontrol_addr; ++ uint32 regcontrol_data; ++ uint32 pllcontrol_addr; ++ uint32 pllcontrol_data; ++ uint32 pmustrapopt; /* 0x668, corerev >= 28 */ ++ uint32 pmu_xtalfreq; /* 0x66C, pmurev >= 10 */ ++ uint32 retention_ctl; /* 0x670 */ ++ uint32 PAD[3]; ++ uint32 retention_grpidx; /* 0x680 */ ++ uint32 retention_grpctl; /* 0x684 */ ++ uint32 PAD[94]; ++ uint16 sromotp[512]; /* 0x800 */ ++#ifdef NFLASH_SUPPORT ++ /* Nand flash MLC controller registers (corerev >= 38) */ ++ uint32 nand_revision; /* 0xC00 */ ++ uint32 nand_cmd_start; ++ uint32 nand_cmd_addr_x; ++ uint32 nand_cmd_addr; ++ uint32 nand_cmd_end_addr; ++ uint32 nand_cs_nand_select; ++ uint32 nand_cs_nand_xor; ++ uint32 PAD; ++ uint32 nand_spare_rd0; ++ uint32 nand_spare_rd4; ++ uint32 nand_spare_rd8; ++ uint32 nand_spare_rd12; ++ uint32 nand_spare_wr0; ++ uint32 nand_spare_wr4; ++ uint32 nand_spare_wr8; ++ uint32 nand_spare_wr12; ++ uint32 nand_acc_control; ++ uint32 PAD; ++ uint32 nand_config; ++ uint32 PAD; ++ uint32 nand_timing_1; ++ uint32 nand_timing_2; ++ uint32 nand_semaphore; ++ uint32 PAD; ++ uint32 nand_devid; ++ uint32 nand_devid_x; ++ uint32 nand_block_lock_status; ++ uint32 nand_intfc_status; ++ uint32 nand_ecc_corr_addr_x; ++ uint32 nand_ecc_corr_addr; ++ uint32 nand_ecc_unc_addr_x; ++ uint32 nand_ecc_unc_addr; ++ uint32 nand_read_error_count; ++ uint32 nand_corr_stat_threshold; ++ uint32 PAD[2]; ++ uint32 nand_read_addr_x; ++ uint32 nand_read_addr; ++ uint32 nand_page_program_addr_x; ++ uint32 nand_page_program_addr; ++ uint32 nand_copy_back_addr_x; ++ uint32 nand_copy_back_addr; ++ uint32 nand_block_erase_addr_x; ++ uint32 nand_block_erase_addr; ++ uint32 nand_inv_read_addr_x; ++ uint32 nand_inv_read_addr; ++ uint32 PAD[2]; ++ uint32 nand_blk_wr_protect; ++ uint32 PAD[3]; ++ uint32 nand_acc_control_cs1; ++ uint32 nand_config_cs1; ++ uint32 nand_timing_1_cs1; ++ uint32 nand_timing_2_cs1; ++ uint32 PAD[20]; ++ uint32 nand_spare_rd16; ++ uint32 nand_spare_rd20; ++ uint32 nand_spare_rd24; ++ uint32 nand_spare_rd28; ++ uint32 nand_cache_addr; ++ uint32 nand_cache_data; ++ uint32 nand_ctrl_config; ++ uint32 nand_ctrl_status; ++#endif /* NFLASH_SUPPORT */ ++ uint32 gci_corecaps0; /* GCI starting at 0xC00 */ ++ uint32 gci_corecaps1; ++ uint32 gci_corecaps2; ++ uint32 gci_corectrl; ++ uint32 gci_corestat; /* 0xC10 */ ++ uint32 PAD[11]; ++ uint32 gci_indirect_addr; /* 0xC40 */ ++ uint32 PAD[111]; ++ uint32 gci_chipctrl; /* 0xE00 */ ++} chipcregs_t; ++ ++#endif /* _LANGUAGE_ASSEMBLY */ ++ ++ ++#define CC_CHIPID 0 ++#define CC_CAPABILITIES 4 ++#define CC_CHIPST 0x2c ++#define CC_EROMPTR 0xfc ++ ++#define CC_OTPST 0x10 ++#define CC_JTAGCMD 0x30 ++#define CC_JTAGIR 0x34 ++#define CC_JTAGDR 0x38 ++#define CC_JTAGCTRL 0x3c ++#define CC_GPIOPU 0x58 ++#define CC_GPIOPD 0x5c ++#define CC_GPIOIN 0x60 ++#define CC_GPIOOUT 0x64 ++#define CC_GPIOOUTEN 0x68 ++#define CC_GPIOCTRL 0x6c ++#define CC_GPIOPOL 0x70 ++#define CC_GPIOINTM 0x74 ++#define CC_WATCHDOG 0x80 ++#define CC_CLKC_N 0x90 ++#define CC_CLKC_M0 0x94 ++#define CC_CLKC_M1 0x98 ++#define CC_CLKC_M2 0x9c ++#define CC_CLKC_M3 0xa0 ++#define CC_CLKDIV 0xa4 ++#define CC_SYS_CLK_CTL 0xc0 ++#define CC_CLK_CTL_ST SI_CLK_CTL_ST ++#define PMU_CTL 0x600 ++#define PMU_CAP 0x604 ++#define PMU_ST 0x608 ++#define PMU_RES_STATE 0x60c ++#define PMU_TIMER 0x614 ++#define PMU_MIN_RES_MASK 0x618 ++#define PMU_MAX_RES_MASK 0x61c ++#define CC_CHIPCTL_ADDR 0x650 ++#define CC_CHIPCTL_DATA 0x654 ++#define PMU_REG_CONTROL_ADDR 0x658 ++#define PMU_REG_CONTROL_DATA 0x65C ++#define PMU_PLL_CONTROL_ADDR 0x660 ++#define PMU_PLL_CONTROL_DATA 0x664 ++#define CC_SROM_OTP 0x800 /* SROM/OTP address space */ ++#define CC_GCI_INDIRECT_ADDR_REG 0xC40 ++#define CC_GCI_CHIP_CTRL_REG 0xE00 ++#define CC_GCI_CC_OFFSET_2 2 ++#define CC_GCI_CC_OFFSET_5 5 ++ ++#ifdef NFLASH_SUPPORT ++/* NAND flash support */ ++#define CC_NAND_REVISION 0xC00 ++#define CC_NAND_CMD_START 0xC04 ++#define CC_NAND_CMD_ADDR 0xC0C ++#define CC_NAND_SPARE_RD_0 0xC20 ++#define CC_NAND_SPARE_RD_4 0xC24 ++#define CC_NAND_SPARE_RD_8 0xC28 ++#define CC_NAND_SPARE_RD_C 0xC2C ++#define CC_NAND_CONFIG 0xC48 ++#define CC_NAND_DEVID 0xC60 ++#define CC_NAND_DEVID_EXT 0xC64 ++#define CC_NAND_INTFC_STATUS 0xC6C ++#endif /* NFLASH_SUPPORT */ ++ ++/* chipid */ ++#define CID_ID_MASK 0x0000ffff /* Chip Id mask */ ++#define CID_REV_MASK 0x000f0000 /* Chip Revision mask */ ++#define CID_REV_SHIFT 16 /* Chip Revision shift */ ++#define CID_PKG_MASK 0x00f00000 /* Package Option mask */ ++#define CID_PKG_SHIFT 20 /* Package Option shift */ ++#define CID_CC_MASK 0x0f000000 /* CoreCount (corerev >= 4) */ ++#define CID_CC_SHIFT 24 ++#define CID_TYPE_MASK 0xf0000000 /* Chip Type */ ++#define CID_TYPE_SHIFT 28 ++ ++/* capabilities */ ++#define CC_CAP_UARTS_MASK 0x00000003 /* Number of UARTs */ ++#define CC_CAP_MIPSEB 0x00000004 /* MIPS is in big-endian mode */ ++#define CC_CAP_UCLKSEL 0x00000018 /* UARTs clock select */ ++#define CC_CAP_UINTCLK 0x00000008 /* UARTs are driven by internal divided clock */ ++#define CC_CAP_UARTGPIO 0x00000020 /* UARTs own GPIOs 15:12 */ ++#define CC_CAP_EXTBUS_MASK 0x000000c0 /* External bus mask */ ++#define CC_CAP_EXTBUS_NONE 0x00000000 /* No ExtBus present */ ++#define CC_CAP_EXTBUS_FULL 0x00000040 /* ExtBus: PCMCIA, IDE & Prog */ ++#define CC_CAP_EXTBUS_PROG 0x00000080 /* ExtBus: ProgIf only */ ++#define CC_CAP_FLASH_MASK 0x00000700 /* Type of flash */ ++#define CC_CAP_PLL_MASK 0x00038000 /* Type of PLL */ ++#define CC_CAP_PWR_CTL 0x00040000 /* Power control */ ++#define CC_CAP_OTPSIZE 0x00380000 /* OTP Size (0 = none) */ ++#define CC_CAP_OTPSIZE_SHIFT 19 /* OTP Size shift */ ++#define CC_CAP_OTPSIZE_BASE 5 /* OTP Size base */ ++#define CC_CAP_JTAGP 0x00400000 /* JTAG Master Present */ ++#define CC_CAP_ROM 0x00800000 /* Internal boot rom active */ ++#define CC_CAP_BKPLN64 0x08000000 /* 64-bit backplane */ ++#define CC_CAP_PMU 0x10000000 /* PMU Present, rev >= 20 */ ++#define CC_CAP_ECI 0x20000000 /* ECI Present, rev >= 21 */ ++#define CC_CAP_SROM 0x40000000 /* Srom Present, rev >= 32 */ ++#define CC_CAP_NFLASH 0x80000000 /* Nand flash present, rev >= 35 */ ++ ++#define CC_CAP2_SECI 0x00000001 /* SECI Present, rev >= 36 */ ++#define CC_CAP2_GSIO 0x00000002 /* GSIO (spi/i2c) present, rev >= 37 */ ++ ++/* capabilities extension */ ++#define CC_CAP_EXT_SECI_PRESENT 0x00000001 /* SECI present */ ++ ++/* PLL type */ ++#define PLL_NONE 0x00000000 ++#define PLL_TYPE1 0x00010000 /* 48MHz base, 3 dividers */ ++#define PLL_TYPE2 0x00020000 /* 48MHz, 4 dividers */ ++#define PLL_TYPE3 0x00030000 /* 25MHz, 2 dividers */ ++#define PLL_TYPE4 0x00008000 /* 48MHz, 4 dividers */ ++#define PLL_TYPE5 0x00018000 /* 25MHz, 4 dividers */ ++#define PLL_TYPE6 0x00028000 /* 100/200 or 120/240 only */ ++#define PLL_TYPE7 0x00038000 /* 25MHz, 4 dividers */ ++ ++/* ILP clock */ ++#define ILP_CLOCK 32000 ++ ++/* ALP clock on pre-PMU chips */ ++#define ALP_CLOCK 20000000 ++ ++/* HT clock */ ++#define HT_CLOCK 80000000 ++ ++/* corecontrol */ ++#define CC_UARTCLKO 0x00000001 /* Drive UART with internal clock */ ++#define CC_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ ++#define CC_ASYNCGPIO 0x00000004 /* 1=generate GPIO interrupt without backplane clock */ ++#define CC_UARTCLKEN 0x00000008 /* enable UART Clock (corerev > = 21 */ ++ ++/* 4321 chipcontrol */ ++#define CHIPCTRL_4321A0_DEFAULT 0x3a4 ++#define CHIPCTRL_4321A1_DEFAULT 0x0a4 ++#define CHIPCTRL_4321_PLL_DOWN 0x800000 /* serdes PLL down override */ ++ ++/* Fields in the otpstatus register in rev >= 21 */ ++#define OTPS_OL_MASK 0x000000ff ++#define OTPS_OL_MFG 0x00000001 /* manuf row is locked */ ++#define OTPS_OL_OR1 0x00000002 /* otp redundancy row 1 is locked */ ++#define OTPS_OL_OR2 0x00000004 /* otp redundancy row 2 is locked */ ++#define OTPS_OL_GU 0x00000008 /* general use region is locked */ ++#define OTPS_GUP_MASK 0x00000f00 ++#define OTPS_GUP_SHIFT 8 ++#define OTPS_GUP_HW 0x00000100 /* h/w subregion is programmed */ ++#define OTPS_GUP_SW 0x00000200 /* s/w subregion is programmed */ ++#define OTPS_GUP_CI 0x00000400 /* chipid/pkgopt subregion is programmed */ ++#define OTPS_GUP_FUSE 0x00000800 /* fuse subregion is programmed */ ++#define OTPS_READY 0x00001000 ++#define OTPS_RV(x) (1 << (16 + (x))) /* redundancy entry valid */ ++#define OTPS_RV_MASK 0x0fff0000 ++#define OTPS_PROGOK 0x40000000 ++ ++/* Fields in the otpcontrol register in rev >= 21 */ ++#define OTPC_PROGSEL 0x00000001 ++#define OTPC_PCOUNT_MASK 0x0000000e ++#define OTPC_PCOUNT_SHIFT 1 ++#define OTPC_VSEL_MASK 0x000000f0 ++#define OTPC_VSEL_SHIFT 4 ++#define OTPC_TMM_MASK 0x00000700 ++#define OTPC_TMM_SHIFT 8 ++#define OTPC_ODM 0x00000800 ++#define OTPC_PROGEN 0x80000000 ++ ++/* Fields in the 40nm otpcontrol register in rev >= 40 */ ++#define OTPC_40NM_PROGSEL_SHIFT 0 ++#define OTPC_40NM_PCOUNT_SHIFT 1 ++#define OTPC_40NM_PCOUNT_WR 0xA ++#define OTPC_40NM_PCOUNT_V1X 0xB ++#define OTPC_40NM_REGCSEL_SHIFT 5 ++#define OTPC_40NM_REGCSEL_DEF 0x4 ++#define OTPC_40NM_PROGIN_SHIFT 8 ++#define OTPC_40NM_R2X_SHIFT 10 ++#define OTPC_40NM_ODM_SHIFT 11 ++#define OTPC_40NM_DF_SHIFT 15 ++#define OTPC_40NM_VSEL_SHIFT 16 ++#define OTPC_40NM_VSEL_WR 0xA ++#define OTPC_40NM_VSEL_V1X 0xA ++#define OTPC_40NM_VSEL_R1X 0x5 ++#define OTPC_40NM_COFAIL_SHIFT 30 ++ ++#define OTPC1_CPCSEL_SHIFT 0 ++#define OTPC1_CPCSEL_DEF 6 ++#define OTPC1_TM_SHIFT 8 ++#define OTPC1_TM_WR 0x84 ++#define OTPC1_TM_V1X 0x84 ++#define OTPC1_TM_R1X 0x4 ++ ++/* Fields in otpprog in rev >= 21 and HND OTP */ ++#define OTPP_COL_MASK 0x000000ff ++#define OTPP_COL_SHIFT 0 ++#define OTPP_ROW_MASK 0x0000ff00 ++#define OTPP_ROW_SHIFT 8 ++#define OTPP_OC_MASK 0x0f000000 ++#define OTPP_OC_SHIFT 24 ++#define OTPP_READERR 0x10000000 ++#define OTPP_VALUE_MASK 0x20000000 ++#define OTPP_VALUE_SHIFT 29 ++#define OTPP_START_BUSY 0x80000000 ++#define OTPP_READ 0x40000000 /* HND OTP */ ++ ++/* Fields in otplayout register */ ++#define OTPL_HWRGN_OFF_MASK 0x00000FFF ++#define OTPL_HWRGN_OFF_SHIFT 0 ++#define OTPL_WRAP_REVID_MASK 0x00F80000 ++#define OTPL_WRAP_REVID_SHIFT 19 ++#define OTPL_WRAP_TYPE_MASK 0x00070000 ++#define OTPL_WRAP_TYPE_SHIFT 16 ++#define OTPL_WRAP_TYPE_65NM 0 ++#define OTPL_WRAP_TYPE_40NM 1 ++ ++/* otplayout reg corerev >= 36 */ ++#define OTP_CISFORMAT_NEW 0x80000000 ++ ++/* Opcodes for OTPP_OC field */ ++#define OTPPOC_READ 0 ++#define OTPPOC_BIT_PROG 1 ++#define OTPPOC_VERIFY 3 ++#define OTPPOC_INIT 4 ++#define OTPPOC_SET 5 ++#define OTPPOC_RESET 6 ++#define OTPPOC_OCST 7 ++#define OTPPOC_ROW_LOCK 8 ++#define OTPPOC_PRESCN_TEST 9 ++ ++/* Opcodes for OTPP_OC field (40NM) */ ++#define OTPPOC_READ_40NM 0 ++#define OTPPOC_PROG_ENABLE_40NM 1 ++#define OTPPOC_PROG_DISABLE_40NM 2 ++#define OTPPOC_VERIFY_40NM 3 ++#define OTPPOC_WORD_VERIFY_1_40NM 4 ++#define OTPPOC_ROW_LOCK_40NM 5 ++#define OTPPOC_STBY_40NM 6 ++#define OTPPOC_WAKEUP_40NM 7 ++#define OTPPOC_WORD_VERIFY_0_40NM 8 ++#define OTPPOC_PRESCN_TEST_40NM 9 ++#define OTPPOC_BIT_PROG_40NM 10 ++#define OTPPOC_WORDPROG_40NM 11 ++#define OTPPOC_BURNIN_40NM 12 ++#define OTPPOC_AUTORELOAD_40NM 13 ++#define OTPPOC_OVST_READ_40NM 14 ++#define OTPPOC_OVST_PROG_40NM 15 ++ ++/* Fields in otplayoutextension */ ++#define OTPLAYOUTEXT_FUSE_MASK 0x3FF ++ ++ ++/* Jtagm characteristics that appeared at a given corerev */ ++#define JTAGM_CREV_OLD 10 /* Old command set, 16bit max IR */ ++#define JTAGM_CREV_IRP 22 /* Able to do pause-ir */ ++#define JTAGM_CREV_RTI 28 /* Able to do return-to-idle */ ++ ++/* jtagcmd */ ++#define JCMD_START 0x80000000 ++#define JCMD_BUSY 0x80000000 ++#define JCMD_STATE_MASK 0x60000000 ++#define JCMD_STATE_TLR 0x00000000 /* Test-logic-reset */ ++#define JCMD_STATE_PIR 0x20000000 /* Pause IR */ ++#define JCMD_STATE_PDR 0x40000000 /* Pause DR */ ++#define JCMD_STATE_RTI 0x60000000 /* Run-test-idle */ ++#define JCMD0_ACC_MASK 0x0000f000 ++#define JCMD0_ACC_IRDR 0x00000000 ++#define JCMD0_ACC_DR 0x00001000 ++#define JCMD0_ACC_IR 0x00002000 ++#define JCMD0_ACC_RESET 0x00003000 ++#define JCMD0_ACC_IRPDR 0x00004000 ++#define JCMD0_ACC_PDR 0x00005000 ++#define JCMD0_IRW_MASK 0x00000f00 ++#define JCMD_ACC_MASK 0x000f0000 /* Changes for corerev 11 */ ++#define JCMD_ACC_IRDR 0x00000000 ++#define JCMD_ACC_DR 0x00010000 ++#define JCMD_ACC_IR 0x00020000 ++#define JCMD_ACC_RESET 0x00030000 ++#define JCMD_ACC_IRPDR 0x00040000 ++#define JCMD_ACC_PDR 0x00050000 ++#define JCMD_ACC_PIR 0x00060000 ++#define JCMD_ACC_IRDR_I 0x00070000 /* rev 28: return to run-test-idle */ ++#define JCMD_ACC_DR_I 0x00080000 /* rev 28: return to run-test-idle */ ++#define JCMD_IRW_MASK 0x00001f00 ++#define JCMD_IRW_SHIFT 8 ++#define JCMD_DRW_MASK 0x0000003f ++ ++/* jtagctrl */ ++#define JCTRL_FORCE_CLK 4 /* Force clock */ ++#define JCTRL_EXT_EN 2 /* Enable external targets */ ++#define JCTRL_EN 1 /* Enable Jtag master */ ++ ++/* Fields in clkdiv */ ++#define CLKD_SFLASH 0x0f000000 ++#define CLKD_SFLASH_SHIFT 24 ++#define CLKD_OTP 0x000f0000 ++#define CLKD_OTP_SHIFT 16 ++#define CLKD_JTAG 0x00000f00 ++#define CLKD_JTAG_SHIFT 8 ++#define CLKD_UART 0x000000ff ++ ++#define CLKD2_SROM 0x00000003 ++ ++/* intstatus/intmask */ ++#define CI_GPIO 0x00000001 /* gpio intr */ ++#define CI_EI 0x00000002 /* extif intr (corerev >= 3) */ ++#define CI_TEMP 0x00000004 /* temp. ctrl intr (corerev >= 15) */ ++#define CI_SIRQ 0x00000008 /* serial IRQ intr (corerev >= 15) */ ++#define CI_ECI 0x00000010 /* eci intr (corerev >= 21) */ ++#define CI_PMU 0x00000020 /* pmu intr (corerev >= 21) */ ++#define CI_UART 0x00000040 /* uart intr (corerev >= 21) */ ++#define CI_WDRESET 0x80000000 /* watchdog reset occurred */ ++ ++/* slow_clk_ctl */ ++#define SCC_SS_MASK 0x00000007 /* slow clock source mask */ ++#define SCC_SS_LPO 0x00000000 /* source of slow clock is LPO */ ++#define SCC_SS_XTAL 0x00000001 /* source of slow clock is crystal */ ++#define SCC_SS_PCI 0x00000002 /* source of slow clock is PCI */ ++#define SCC_LF 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */ ++#define SCC_LP 0x00000400 /* LPOPowerDown, 1: LPO is disabled, ++ * 0: LPO is enabled ++ */ ++#define SCC_FS 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, ++ * 0: power logic control ++ */ ++#define SCC_IP 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors ++ * PLL clock disable requests from core ++ */ ++#define SCC_XC 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't ++ * disable crystal when appropriate ++ */ ++#define SCC_XP 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */ ++#define SCC_CD_MASK 0xffff0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */ ++#define SCC_CD_SHIFT 16 ++ ++/* system_clk_ctl */ ++#define SYCC_IE 0x00000001 /* ILPen: Enable Idle Low Power */ ++#define SYCC_AE 0x00000002 /* ALPen: Enable Active Low Power */ ++#define SYCC_FP 0x00000004 /* ForcePLLOn */ ++#define SYCC_AR 0x00000008 /* Force ALP (or HT if ALPen is not set */ ++#define SYCC_HR 0x00000010 /* Force HT */ ++#define SYCC_CD_MASK 0xffff0000 /* ClkDiv (ILP = 1/(4 * (divisor + 1)) */ ++#define SYCC_CD_SHIFT 16 ++ ++/* Indirect backplane access */ ++#define BPIA_BYTEEN 0x0000000f ++#define BPIA_SZ1 0x00000001 ++#define BPIA_SZ2 0x00000003 ++#define BPIA_SZ4 0x00000007 ++#define BPIA_SZ8 0x0000000f ++#define BPIA_WRITE 0x00000100 ++#define BPIA_START 0x00000200 ++#define BPIA_BUSY 0x00000200 ++#define BPIA_ERROR 0x00000400 ++ ++/* pcmcia/prog/flash_config */ ++#define CF_EN 0x00000001 /* enable */ ++#define CF_EM_MASK 0x0000000e /* mode */ ++#define CF_EM_SHIFT 1 ++#define CF_EM_FLASH 0 /* flash/asynchronous mode */ ++#define CF_EM_SYNC 2 /* synchronous mode */ ++#define CF_EM_PCMCIA 4 /* pcmcia mode */ ++#define CF_DS 0x00000010 /* destsize: 0=8bit, 1=16bit */ ++#define CF_BS 0x00000020 /* byteswap */ ++#define CF_CD_MASK 0x000000c0 /* clock divider */ ++#define CF_CD_SHIFT 6 ++#define CF_CD_DIV2 0x00000000 /* backplane/2 */ ++#define CF_CD_DIV3 0x00000040 /* backplane/3 */ ++#define CF_CD_DIV4 0x00000080 /* backplane/4 */ ++#define CF_CE 0x00000100 /* clock enable */ ++#define CF_SB 0x00000200 /* size/bytestrobe (synch only) */ ++ ++/* pcmcia_memwait */ ++#define PM_W0_MASK 0x0000003f /* waitcount0 */ ++#define PM_W1_MASK 0x00001f00 /* waitcount1 */ ++#define PM_W1_SHIFT 8 ++#define PM_W2_MASK 0x001f0000 /* waitcount2 */ ++#define PM_W2_SHIFT 16 ++#define PM_W3_MASK 0x1f000000 /* waitcount3 */ ++#define PM_W3_SHIFT 24 ++ ++/* pcmcia_attrwait */ ++#define PA_W0_MASK 0x0000003f /* waitcount0 */ ++#define PA_W1_MASK 0x00001f00 /* waitcount1 */ ++#define PA_W1_SHIFT 8 ++#define PA_W2_MASK 0x001f0000 /* waitcount2 */ ++#define PA_W2_SHIFT 16 ++#define PA_W3_MASK 0x1f000000 /* waitcount3 */ ++#define PA_W3_SHIFT 24 ++ ++/* pcmcia_iowait */ ++#define PI_W0_MASK 0x0000003f /* waitcount0 */ ++#define PI_W1_MASK 0x00001f00 /* waitcount1 */ ++#define PI_W1_SHIFT 8 ++#define PI_W2_MASK 0x001f0000 /* waitcount2 */ ++#define PI_W2_SHIFT 16 ++#define PI_W3_MASK 0x1f000000 /* waitcount3 */ ++#define PI_W3_SHIFT 24 ++ ++/* prog_waitcount */ ++#define PW_W0_MASK 0x0000001f /* waitcount0 */ ++#define PW_W1_MASK 0x00001f00 /* waitcount1 */ ++#define PW_W1_SHIFT 8 ++#define PW_W2_MASK 0x001f0000 /* waitcount2 */ ++#define PW_W2_SHIFT 16 ++#define PW_W3_MASK 0x1f000000 /* waitcount3 */ ++#define PW_W3_SHIFT 24 ++ ++#define PW_W0 0x0000000c ++#define PW_W1 0x00000a00 ++#define PW_W2 0x00020000 ++#define PW_W3 0x01000000 ++ ++/* flash_waitcount */ ++#define FW_W0_MASK 0x0000003f /* waitcount0 */ ++#define FW_W1_MASK 0x00001f00 /* waitcount1 */ ++#define FW_W1_SHIFT 8 ++#define FW_W2_MASK 0x001f0000 /* waitcount2 */ ++#define FW_W2_SHIFT 16 ++#define FW_W3_MASK 0x1f000000 /* waitcount3 */ ++#define FW_W3_SHIFT 24 ++ ++/* When Srom support present, fields in sromcontrol */ ++#define SRC_START 0x80000000 ++#define SRC_BUSY 0x80000000 ++#define SRC_OPCODE 0x60000000 ++#define SRC_OP_READ 0x00000000 ++#define SRC_OP_WRITE 0x20000000 ++#define SRC_OP_WRDIS 0x40000000 ++#define SRC_OP_WREN 0x60000000 ++#define SRC_OTPSEL 0x00000010 ++#define SRC_LOCK 0x00000008 ++#define SRC_SIZE_MASK 0x00000006 ++#define SRC_SIZE_1K 0x00000000 ++#define SRC_SIZE_4K 0x00000002 ++#define SRC_SIZE_16K 0x00000004 ++#define SRC_SIZE_SHIFT 1 ++#define SRC_PRESENT 0x00000001 ++ ++/* Fields in pmucontrol */ ++#define PCTL_ILP_DIV_MASK 0xffff0000 ++#define PCTL_ILP_DIV_SHIFT 16 ++#define PCTL_PLL_PLLCTL_UPD 0x00000400 /* rev 2 */ ++#define PCTL_NOILP_ON_WAIT 0x00000200 /* rev 1 */ ++#define PCTL_HT_REQ_EN 0x00000100 ++#define PCTL_ALP_REQ_EN 0x00000080 ++#define PCTL_XTALFREQ_MASK 0x0000007c ++#define PCTL_XTALFREQ_SHIFT 2 ++#define PCTL_ILP_DIV_EN 0x00000002 ++#define PCTL_LPO_SEL 0x00000001 ++ ++/* Fields in clkstretch */ ++#define CSTRETCH_HT 0xffff0000 ++#define CSTRETCH_ALP 0x0000ffff ++ ++/* gpiotimerval */ ++#define GPIO_ONTIME_SHIFT 16 ++ ++/* clockcontrol_n */ ++#define CN_N1_MASK 0x3f /* n1 control */ ++#define CN_N2_MASK 0x3f00 /* n2 control */ ++#define CN_N2_SHIFT 8 ++#define CN_PLLC_MASK 0xf0000 /* pll control */ ++#define CN_PLLC_SHIFT 16 ++ ++/* clockcontrol_sb/pci/uart */ ++#define CC_M1_MASK 0x3f /* m1 control */ ++#define CC_M2_MASK 0x3f00 /* m2 control */ ++#define CC_M2_SHIFT 8 ++#define CC_M3_MASK 0x3f0000 /* m3 control */ ++#define CC_M3_SHIFT 16 ++#define CC_MC_MASK 0x1f000000 /* mux control */ ++#define CC_MC_SHIFT 24 ++ ++/* N3M Clock control magic field values */ ++#define CC_F6_2 0x02 /* A factor of 2 in */ ++#define CC_F6_3 0x03 /* 6-bit fields like */ ++#define CC_F6_4 0x05 /* N1, M1 or M3 */ ++#define CC_F6_5 0x09 ++#define CC_F6_6 0x11 ++#define CC_F6_7 0x21 ++ ++#define CC_F5_BIAS 5 /* 5-bit fields get this added */ ++ ++#define CC_MC_BYPASS 0x08 ++#define CC_MC_M1 0x04 ++#define CC_MC_M1M2 0x02 ++#define CC_MC_M1M2M3 0x01 ++#define CC_MC_M1M3 0x11 ++ ++/* Type 2 Clock control magic field values */ ++#define CC_T2_BIAS 2 /* n1, n2, m1 & m3 bias */ ++#define CC_T2M2_BIAS 3 /* m2 bias */ ++ ++#define CC_T2MC_M1BYP 1 ++#define CC_T2MC_M2BYP 2 ++#define CC_T2MC_M3BYP 4 ++ ++/* Type 6 Clock control magic field values */ ++#define CC_T6_MMASK 1 /* bits of interest in m */ ++#define CC_T6_M0 120000000 /* sb clock for m = 0 */ ++#define CC_T6_M1 100000000 /* sb clock for m = 1 */ ++#define SB2MIPS_T6(sb) (2 * (sb)) ++ ++/* Common clock base */ ++#define CC_CLOCK_BASE1 24000000 /* Half the clock freq */ ++#define CC_CLOCK_BASE2 12500000 /* Alternate crystal on some PLLs */ ++ ++/* Clock control values for 200MHz in 5350 */ ++#define CLKC_5350_N 0x0311 ++#define CLKC_5350_M 0x04020009 ++ ++/* Flash types in the chipcommon capabilities register */ ++#define FLASH_NONE 0x000 /* No flash */ ++#define SFLASH_ST 0x100 /* ST serial flash */ ++#define SFLASH_AT 0x200 /* Atmel serial flash */ ++#define NFLASH 0x300 ++#define PFLASH 0x700 /* Parallel flash */ ++ ++/* Bits in the ExtBus config registers */ ++#define CC_CFG_EN 0x0001 /* Enable */ ++#define CC_CFG_EM_MASK 0x000e /* Extif Mode */ ++#define CC_CFG_EM_ASYNC 0x0000 /* Async/Parallel flash */ ++#define CC_CFG_EM_SYNC 0x0002 /* Synchronous */ ++#define CC_CFG_EM_PCMCIA 0x0004 /* PCMCIA */ ++#define CC_CFG_EM_IDE 0x0006 /* IDE */ ++#define CC_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */ ++#define CC_CFG_CD_MASK 0x00e0 /* Sync: Clock divisor, rev >= 20 */ ++#define CC_CFG_CE 0x0100 /* Sync: Clock enable, rev >= 20 */ ++#define CC_CFG_SB 0x0200 /* Sync: Size/Bytestrobe, rev >= 20 */ ++#define CC_CFG_IS 0x0400 /* Extif Sync Clk Select, rev >= 20 */ ++ ++/* ExtBus address space */ ++#define CC_EB_BASE 0x1a000000 /* Chipc ExtBus base address */ ++#define CC_EB_PCMCIA_MEM 0x1a000000 /* PCMCIA 0 memory base address */ ++#define CC_EB_PCMCIA_IO 0x1a200000 /* PCMCIA 0 I/O base address */ ++#define CC_EB_PCMCIA_CFG 0x1a400000 /* PCMCIA 0 config base address */ ++#define CC_EB_IDE 0x1a800000 /* IDE memory base */ ++#define CC_EB_PCMCIA1_MEM 0x1a800000 /* PCMCIA 1 memory base address */ ++#define CC_EB_PCMCIA1_IO 0x1aa00000 /* PCMCIA 1 I/O base address */ ++#define CC_EB_PCMCIA1_CFG 0x1ac00000 /* PCMCIA 1 config base address */ ++#define CC_EB_PROGIF 0x1b000000 /* ProgIF Async/Sync base address */ ++ ++ ++/* Start/busy bit in flashcontrol */ ++#define SFLASH_OPCODE 0x000000ff ++#define SFLASH_ACTION 0x00000700 ++#define SFLASH_CS_ACTIVE 0x00001000 /* Chip Select Active, rev >= 20 */ ++#define SFLASH_START 0x80000000 ++#define SFLASH_BUSY SFLASH_START ++ ++/* flashcontrol action codes */ ++#define SFLASH_ACT_OPONLY 0x0000 /* Issue opcode only */ ++#define SFLASH_ACT_OP1D 0x0100 /* opcode + 1 data byte */ ++#define SFLASH_ACT_OP3A 0x0200 /* opcode + 3 addr bytes */ ++#define SFLASH_ACT_OP3A1D 0x0300 /* opcode + 3 addr & 1 data bytes */ ++#define SFLASH_ACT_OP3A4D 0x0400 /* opcode + 3 addr & 4 data bytes */ ++#define SFLASH_ACT_OP3A4X4D 0x0500 /* opcode + 3 addr, 4 don't care & 4 data bytes */ ++#define SFLASH_ACT_OP3A1X4D 0x0700 /* opcode + 3 addr, 1 don't care & 4 data bytes */ ++ ++/* flashcontrol action+opcodes for ST flashes */ ++#define SFLASH_ST_WREN 0x0006 /* Write Enable */ ++#define SFLASH_ST_WRDIS 0x0004 /* Write Disable */ ++#define SFLASH_ST_RDSR 0x0105 /* Read Status Register */ ++#define SFLASH_ST_WRSR 0x0101 /* Write Status Register */ ++#define SFLASH_ST_READ 0x0303 /* Read Data Bytes */ ++#define SFLASH_ST_PP 0x0302 /* Page Program */ ++#define SFLASH_ST_SE 0x02d8 /* Sector Erase */ ++#define SFLASH_ST_BE 0x00c7 /* Bulk Erase */ ++#define SFLASH_ST_DP 0x00b9 /* Deep Power-down */ ++#define SFLASH_ST_RES 0x03ab /* Read Electronic Signature */ ++#define SFLASH_ST_CSA 0x1000 /* Keep chip select asserted */ ++#define SFLASH_ST_SSE 0x0220 /* Sub-sector Erase */ ++ ++#define SFLASH_MXIC_RDID 0x0390 /* Read Manufacture ID */ ++#define SFLASH_MXIC_MFID 0xc2 /* MXIC Manufacture ID */ ++ ++/* Status register bits for ST flashes */ ++#define SFLASH_ST_WIP 0x01 /* Write In Progress */ ++#define SFLASH_ST_WEL 0x02 /* Write Enable Latch */ ++#define SFLASH_ST_BP_MASK 0x1c /* Block Protect */ ++#define SFLASH_ST_BP_SHIFT 2 ++#define SFLASH_ST_SRWD 0x80 /* Status Register Write Disable */ ++ ++/* flashcontrol action+opcodes for Atmel flashes */ ++#define SFLASH_AT_READ 0x07e8 ++#define SFLASH_AT_PAGE_READ 0x07d2 ++#define SFLASH_AT_BUF1_READ ++#define SFLASH_AT_BUF2_READ ++#define SFLASH_AT_STATUS 0x01d7 ++#define SFLASH_AT_BUF1_WRITE 0x0384 ++#define SFLASH_AT_BUF2_WRITE 0x0387 ++#define SFLASH_AT_BUF1_ERASE_PROGRAM 0x0283 ++#define SFLASH_AT_BUF2_ERASE_PROGRAM 0x0286 ++#define SFLASH_AT_BUF1_PROGRAM 0x0288 ++#define SFLASH_AT_BUF2_PROGRAM 0x0289 ++#define SFLASH_AT_PAGE_ERASE 0x0281 ++#define SFLASH_AT_BLOCK_ERASE 0x0250 ++#define SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382 ++#define SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385 ++#define SFLASH_AT_BUF1_LOAD 0x0253 ++#define SFLASH_AT_BUF2_LOAD 0x0255 ++#define SFLASH_AT_BUF1_COMPARE 0x0260 ++#define SFLASH_AT_BUF2_COMPARE 0x0261 ++#define SFLASH_AT_BUF1_REPROGRAM 0x0258 ++#define SFLASH_AT_BUF2_REPROGRAM 0x0259 ++ ++/* Status register bits for Atmel flashes */ ++#define SFLASH_AT_READY 0x80 ++#define SFLASH_AT_MISMATCH 0x40 ++#define SFLASH_AT_ID_MASK 0x38 ++#define SFLASH_AT_ID_SHIFT 3 ++ ++/* SPI register bits, corerev >= 37 */ ++#define GSIO_START 0x80000000 ++#define GSIO_BUSY GSIO_START ++ ++/* ++ * These are the UART port assignments, expressed as offsets from the base ++ * register. These assignments should hold for any serial port based on ++ * a 8250, 16450, or 16550(A). ++ */ ++ ++#define UART_RX 0 /* In: Receive buffer (DLAB=0) */ ++#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */ ++#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */ ++#define UART_IER 1 /* In/Out: Interrupt Enable Register (DLAB=0) */ ++#define UART_DLM 1 /* Out: Divisor Latch High (DLAB=1) */ ++#define UART_IIR 2 /* In: Interrupt Identity Register */ ++#define UART_FCR 2 /* Out: FIFO Control Register */ ++#define UART_LCR 3 /* Out: Line Control Register */ ++#define UART_MCR 4 /* Out: Modem Control Register */ ++#define UART_LSR 5 /* In: Line Status Register */ ++#define UART_MSR 6 /* In: Modem Status Register */ ++#define UART_SCR 7 /* I/O: Scratch Register */ ++#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ ++#define UART_LCR_WLEN8 0x03 /* Word length: 8 bits */ ++#define UART_MCR_OUT2 0x08 /* MCR GPIO out 2 */ ++#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ ++#define UART_LSR_RX_FIFO 0x80 /* Receive FIFO error */ ++#define UART_LSR_TDHR 0x40 /* Data-hold-register empty */ ++#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ ++#define UART_LSR_BREAK 0x10 /* Break interrupt */ ++#define UART_LSR_FRAMING 0x08 /* Framing error */ ++#define UART_LSR_PARITY 0x04 /* Parity error */ ++#define UART_LSR_OVERRUN 0x02 /* Overrun error */ ++#define UART_LSR_RXRDY 0x01 /* Receiver ready */ ++#define UART_FCR_FIFO_ENABLE 1 /* FIFO control register bit controlling FIFO enable/disable */ ++ ++/* Interrupt Identity Register (IIR) bits */ ++#define UART_IIR_FIFO_MASK 0xc0 /* IIR FIFO disable/enabled mask */ ++#define UART_IIR_INT_MASK 0xf /* IIR interrupt ID source */ ++#define UART_IIR_MDM_CHG 0x0 /* Modem status changed */ ++#define UART_IIR_NOINT 0x1 /* No interrupt pending */ ++#define UART_IIR_THRE 0x2 /* THR empty */ ++#define UART_IIR_RCVD_DATA 0x4 /* Received data available */ ++#define UART_IIR_RCVR_STATUS 0x6 /* Receiver status */ ++#define UART_IIR_CHAR_TIME 0xc /* Character time */ ++ ++/* Interrupt Enable Register (IER) bits */ ++#define UART_IER_EDSSI 8 /* enable modem status interrupt */ ++#define UART_IER_ELSI 4 /* enable receiver line status interrupt */ ++#define UART_IER_ETBEI 2 /* enable transmitter holding register empty interrupt */ ++#define UART_IER_ERBFI 1 /* enable data available interrupt */ ++ ++/* pmustatus */ ++#define PST_EXTLPOAVAIL 0x0100 ++#define PST_WDRESET 0x0080 ++#define PST_INTPEND 0x0040 ++#define PST_SBCLKST 0x0030 ++#define PST_SBCLKST_ILP 0x0010 ++#define PST_SBCLKST_ALP 0x0020 ++#define PST_SBCLKST_HT 0x0030 ++#define PST_ALPAVAIL 0x0008 ++#define PST_HTAVAIL 0x0004 ++#define PST_RESINIT 0x0003 ++ ++/* pmucapabilities */ ++#define PCAP_REV_MASK 0x000000ff ++#define PCAP_RC_MASK 0x00001f00 ++#define PCAP_RC_SHIFT 8 ++#define PCAP_TC_MASK 0x0001e000 ++#define PCAP_TC_SHIFT 13 ++#define PCAP_PC_MASK 0x001e0000 ++#define PCAP_PC_SHIFT 17 ++#define PCAP_VC_MASK 0x01e00000 ++#define PCAP_VC_SHIFT 21 ++#define PCAP_CC_MASK 0x1e000000 ++#define PCAP_CC_SHIFT 25 ++#define PCAP5_PC_MASK 0x003e0000 /* PMU corerev >= 5 */ ++#define PCAP5_PC_SHIFT 17 ++#define PCAP5_VC_MASK 0x07c00000 ++#define PCAP5_VC_SHIFT 22 ++#define PCAP5_CC_MASK 0xf8000000 ++#define PCAP5_CC_SHIFT 27 ++ ++/* PMU Resource Request Timer registers */ ++/* This is based on PmuRev0 */ ++#define PRRT_TIME_MASK 0x03ff ++#define PRRT_INTEN 0x0400 ++#define PRRT_REQ_ACTIVE 0x0800 ++#define PRRT_ALP_REQ 0x1000 ++#define PRRT_HT_REQ 0x2000 ++#define PRRT_HQ_REQ 0x4000 ++ ++/* PMU resource bit position */ ++#define PMURES_BIT(bit) (1 << (bit)) ++ ++/* PMU resource number limit */ ++#define PMURES_MAX_RESNUM 30 ++ ++/* PMU chip control0 register */ ++#define PMU_CHIPCTL0 0 ++ ++/* clock req types */ ++#define PMU_CC1_CLKREQ_TYPE_SHIFT 19 ++#define PMU_CC1_CLKREQ_TYPE_MASK (1 << PMU_CC1_CLKREQ_TYPE_SHIFT) ++ ++#define CLKREQ_TYPE_CONFIG_OPENDRAIN 0 ++#define CLKREQ_TYPE_CONFIG_PUSHPULL 1 ++ ++/* PMU chip control1 register */ ++#define PMU_CHIPCTL1 1 ++#define PMU_CC1_RXC_DLL_BYPASS 0x00010000 ++ ++#define PMU_CC1_IF_TYPE_MASK 0x00000030 ++#define PMU_CC1_IF_TYPE_RMII 0x00000000 ++#define PMU_CC1_IF_TYPE_MII 0x00000010 ++#define PMU_CC1_IF_TYPE_RGMII 0x00000020 ++ ++#define PMU_CC1_SW_TYPE_MASK 0x000000c0 ++#define PMU_CC1_SW_TYPE_EPHY 0x00000000 ++#define PMU_CC1_SW_TYPE_EPHYMII 0x00000040 ++#define PMU_CC1_SW_TYPE_EPHYRMII 0x00000080 ++#define PMU_CC1_SW_TYPE_RGMII 0x000000c0 ++ ++/* PMU chip control2 register */ ++#define PMU_CHIPCTL2 2 ++ ++/* PMU chip control3 register */ ++#define PMU_CHIPCTL3 3 ++ ++#define PMU_CC3_ENABLE_SDIO_WAKEUP_SHIFT 19 ++#define PMU_CC3_ENABLE_RF_SHIFT 22 ++#define PMU_CC3_RF_DISABLE_IVALUE_SHIFT 23 ++ ++ ++/* PMU corerev and chip specific PLL controls. ++ * PMU_PLL_XX where is PMU corerev and is an arbitrary number ++ * to differentiate different PLLs controlled by the same PMU rev. ++ */ ++/* pllcontrol registers */ ++/* PDIV, div_phy, div_arm, div_adc, dith_sel, ioff, kpd_scale, lsb_sel, mash_sel, lf_c & lf_r */ ++#define PMU0_PLL0_PLLCTL0 0 ++#define PMU0_PLL0_PC0_PDIV_MASK 1 ++#define PMU0_PLL0_PC0_PDIV_FREQ 25000 ++#define PMU0_PLL0_PC0_DIV_ARM_MASK 0x00000038 ++#define PMU0_PLL0_PC0_DIV_ARM_SHIFT 3 ++#define PMU0_PLL0_PC0_DIV_ARM_BASE 8 ++ ++/* PC0_DIV_ARM for PLLOUT_ARM */ ++#define PMU0_PLL0_PC0_DIV_ARM_110MHZ 0 ++#define PMU0_PLL0_PC0_DIV_ARM_97_7MHZ 1 ++#define PMU0_PLL0_PC0_DIV_ARM_88MHZ 2 ++#define PMU0_PLL0_PC0_DIV_ARM_80MHZ 3 /* Default */ ++#define PMU0_PLL0_PC0_DIV_ARM_73_3MHZ 4 ++#define PMU0_PLL0_PC0_DIV_ARM_67_7MHZ 5 ++#define PMU0_PLL0_PC0_DIV_ARM_62_9MHZ 6 ++#define PMU0_PLL0_PC0_DIV_ARM_58_6MHZ 7 ++ ++/* Wildcard base, stop_mod, en_lf_tp, en_cal & lf_r2 */ ++#define PMU0_PLL0_PLLCTL1 1 ++#define PMU0_PLL0_PC1_WILD_INT_MASK 0xf0000000 ++#define PMU0_PLL0_PC1_WILD_INT_SHIFT 28 ++#define PMU0_PLL0_PC1_WILD_FRAC_MASK 0x0fffff00 ++#define PMU0_PLL0_PC1_WILD_FRAC_SHIFT 8 ++#define PMU0_PLL0_PC1_STOP_MOD 0x00000040 ++ ++/* Wildcard base, vco_calvar, vco_swc, vco_var_selref, vso_ical & vco_sel_avdd */ ++#define PMU0_PLL0_PLLCTL2 2 ++#define PMU0_PLL0_PC2_WILD_INT_MASK 0xf ++#define PMU0_PLL0_PC2_WILD_INT_SHIFT 4 ++ ++/* pllcontrol registers */ ++/* ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, p1div, p2div, _bypass_sdmod */ ++#define PMU1_PLL0_PLLCTL0 0 ++#define PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000 ++#define PMU1_PLL0_PC0_P1DIV_SHIFT 20 ++#define PMU1_PLL0_PC0_P2DIV_MASK 0x0f000000 ++#define PMU1_PLL0_PC0_P2DIV_SHIFT 24 ++ ++/* mdiv */ ++#define PMU1_PLL0_PLLCTL1 1 ++#define PMU1_PLL0_PC1_M1DIV_MASK 0x000000ff ++#define PMU1_PLL0_PC1_M1DIV_SHIFT 0 ++#define PMU1_PLL0_PC1_M2DIV_MASK 0x0000ff00 ++#define PMU1_PLL0_PC1_M2DIV_SHIFT 8 ++#define PMU1_PLL0_PC1_M3DIV_MASK 0x00ff0000 ++#define PMU1_PLL0_PC1_M3DIV_SHIFT 16 ++#define PMU1_PLL0_PC1_M4DIV_MASK 0xff000000 ++#define PMU1_PLL0_PC1_M4DIV_SHIFT 24 ++#define PMU1_PLL0_PC1_M4DIV_BY_9 9 ++#define PMU1_PLL0_PC1_M4DIV_BY_18 0x12 ++#define PMU1_PLL0_PC1_M4DIV_BY_36 0x24 ++ ++#define DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT 8 ++#define DOT11MAC_880MHZ_CLK_DIVISOR_MASK (0xFF << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) ++#define DOT11MAC_880MHZ_CLK_DIVISOR_VAL (0xE << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) ++ ++/* mdiv, ndiv_dither_mfb, ndiv_mode, ndiv_int */ ++#define PMU1_PLL0_PLLCTL2 2 ++#define PMU1_PLL0_PC2_M5DIV_MASK 0x000000ff ++#define PMU1_PLL0_PC2_M5DIV_SHIFT 0 ++#define PMU1_PLL0_PC2_M5DIV_BY_12 0xc ++#define PMU1_PLL0_PC2_M5DIV_BY_18 0x12 ++#define PMU1_PLL0_PC2_M5DIV_BY_36 0x24 ++#define PMU1_PLL0_PC2_M6DIV_MASK 0x0000ff00 ++#define PMU1_PLL0_PC2_M6DIV_SHIFT 8 ++#define PMU1_PLL0_PC2_M6DIV_BY_18 0x12 ++#define PMU1_PLL0_PC2_M6DIV_BY_36 0x24 ++#define PMU1_PLL0_PC2_NDIV_MODE_MASK 0x000e0000 ++#define PMU1_PLL0_PC2_NDIV_MODE_SHIFT 17 ++#define PMU1_PLL0_PC2_NDIV_MODE_MASH 1 ++#define PMU1_PLL0_PC2_NDIV_MODE_MFB 2 /* recommended for 4319 */ ++#define PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000 ++#define PMU1_PLL0_PC2_NDIV_INT_SHIFT 20 ++ ++/* ndiv_frac */ ++#define PMU1_PLL0_PLLCTL3 3 ++#define PMU1_PLL0_PC3_NDIV_FRAC_MASK 0x00ffffff ++#define PMU1_PLL0_PC3_NDIV_FRAC_SHIFT 0 ++ ++/* pll_ctrl */ ++#define PMU1_PLL0_PLLCTL4 4 ++ ++/* pll_ctrl, vco_rng, clkdrive_ch */ ++#define PMU1_PLL0_PLLCTL5 5 ++#define PMU1_PLL0_PC5_CLK_DRV_MASK 0xffffff00 ++#define PMU1_PLL0_PC5_CLK_DRV_SHIFT 8 ++ ++/* PMU rev 2 control words */ ++#define PMU2_PHY_PLL_PLLCTL 4 ++#define PMU2_SI_PLL_PLLCTL 10 ++ ++/* PMU rev 2 */ ++/* pllcontrol registers */ ++/* ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, p1div, p2div, _bypass_sdmod */ ++#define PMU2_PLL_PLLCTL0 0 ++#define PMU2_PLL_PC0_P1DIV_MASK 0x00f00000 ++#define PMU2_PLL_PC0_P1DIV_SHIFT 20 ++#define PMU2_PLL_PC0_P2DIV_MASK 0x0f000000 ++#define PMU2_PLL_PC0_P2DIV_SHIFT 24 ++ ++/* mdiv */ ++#define PMU2_PLL_PLLCTL1 1 ++#define PMU2_PLL_PC1_M1DIV_MASK 0x000000ff ++#define PMU2_PLL_PC1_M1DIV_SHIFT 0 ++#define PMU2_PLL_PC1_M2DIV_MASK 0x0000ff00 ++#define PMU2_PLL_PC1_M2DIV_SHIFT 8 ++#define PMU2_PLL_PC1_M3DIV_MASK 0x00ff0000 ++#define PMU2_PLL_PC1_M3DIV_SHIFT 16 ++#define PMU2_PLL_PC1_M4DIV_MASK 0xff000000 ++#define PMU2_PLL_PC1_M4DIV_SHIFT 24 ++ ++/* mdiv, ndiv_dither_mfb, ndiv_mode, ndiv_int */ ++#define PMU2_PLL_PLLCTL2 2 ++#define PMU2_PLL_PC2_M5DIV_MASK 0x000000ff ++#define PMU2_PLL_PC2_M5DIV_SHIFT 0 ++#define PMU2_PLL_PC2_M6DIV_MASK 0x0000ff00 ++#define PMU2_PLL_PC2_M6DIV_SHIFT 8 ++#define PMU2_PLL_PC2_NDIV_MODE_MASK 0x000e0000 ++#define PMU2_PLL_PC2_NDIV_MODE_SHIFT 17 ++#define PMU2_PLL_PC2_NDIV_INT_MASK 0x1ff00000 ++#define PMU2_PLL_PC2_NDIV_INT_SHIFT 20 ++ ++/* ndiv_frac */ ++#define PMU2_PLL_PLLCTL3 3 ++#define PMU2_PLL_PC3_NDIV_FRAC_MASK 0x00ffffff ++#define PMU2_PLL_PC3_NDIV_FRAC_SHIFT 0 ++ ++/* pll_ctrl */ ++#define PMU2_PLL_PLLCTL4 4 ++ ++/* pll_ctrl, vco_rng, clkdrive_ch */ ++#define PMU2_PLL_PLLCTL5 5 ++#define PMU2_PLL_PC5_CLKDRIVE_CH1_MASK 0x00000f00 ++#define PMU2_PLL_PC5_CLKDRIVE_CH1_SHIFT 8 ++#define PMU2_PLL_PC5_CLKDRIVE_CH2_MASK 0x0000f000 ++#define PMU2_PLL_PC5_CLKDRIVE_CH2_SHIFT 12 ++#define PMU2_PLL_PC5_CLKDRIVE_CH3_MASK 0x000f0000 ++#define PMU2_PLL_PC5_CLKDRIVE_CH3_SHIFT 16 ++#define PMU2_PLL_PC5_CLKDRIVE_CH4_MASK 0x00f00000 ++#define PMU2_PLL_PC5_CLKDRIVE_CH4_SHIFT 20 ++#define PMU2_PLL_PC5_CLKDRIVE_CH5_MASK 0x0f000000 ++#define PMU2_PLL_PC5_CLKDRIVE_CH5_SHIFT 24 ++#define PMU2_PLL_PC5_CLKDRIVE_CH6_MASK 0xf0000000 ++#define PMU2_PLL_PC5_CLKDRIVE_CH6_SHIFT 28 ++ ++/* PMU rev 5 (& 6) */ ++#define PMU5_PLL_P1P2_OFF 0 ++#define PMU5_PLL_P1_MASK 0x0f000000 ++#define PMU5_PLL_P1_SHIFT 24 ++#define PMU5_PLL_P2_MASK 0x00f00000 ++#define PMU5_PLL_P2_SHIFT 20 ++#define PMU5_PLL_M14_OFF 1 ++#define PMU5_PLL_MDIV_MASK 0x000000ff ++#define PMU5_PLL_MDIV_WIDTH 8 ++#define PMU5_PLL_NM5_OFF 2 ++#define PMU5_PLL_NDIV_MASK 0xfff00000 ++#define PMU5_PLL_NDIV_SHIFT 20 ++#define PMU5_PLL_NDIV_MODE_MASK 0x000e0000 ++#define PMU5_PLL_NDIV_MODE_SHIFT 17 ++#define PMU5_PLL_FMAB_OFF 3 ++#define PMU5_PLL_MRAT_MASK 0xf0000000 ++#define PMU5_PLL_MRAT_SHIFT 28 ++#define PMU5_PLL_ABRAT_MASK 0x08000000 ++#define PMU5_PLL_ABRAT_SHIFT 27 ++#define PMU5_PLL_FDIV_MASK 0x07ffffff ++#define PMU5_PLL_PLLCTL_OFF 4 ++#define PMU5_PLL_PCHI_OFF 5 ++#define PMU5_PLL_PCHI_MASK 0x0000003f ++ ++/* pmu XtalFreqRatio */ ++#define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF ++#define PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000 ++#define PMU_XTALFREQ_REG_MEASURE_SHIFT 31 ++ ++/* Divider allocation in 4716/47162/5356/5357 */ ++#define PMU5_MAINPLL_CPU 1 ++#define PMU5_MAINPLL_MEM 2 ++#define PMU5_MAINPLL_SI 3 ++ ++/* 4706 PMU */ ++#define PMU4706_MAINPLL_PLL0 0 ++#define PMU6_4706_PROCPLL_OFF 4 /* The CPU PLL */ ++#define PMU6_4706_PROC_P2DIV_MASK 0x000f0000 ++#define PMU6_4706_PROC_P2DIV_SHIFT 16 ++#define PMU6_4706_PROC_P1DIV_MASK 0x0000f000 ++#define PMU6_4706_PROC_P1DIV_SHIFT 12 ++#define PMU6_4706_PROC_NDIV_INT_MASK 0x00000ff8 ++#define PMU6_4706_PROC_NDIV_INT_SHIFT 3 ++#define PMU6_4706_PROC_NDIV_MODE_MASK 0x00000007 ++#define PMU6_4706_PROC_NDIV_MODE_SHIFT 0 ++ ++#define PMU7_PLL_PLLCTL7 7 ++#define PMU7_PLL_CTL7_M4DIV_MASK 0xff000000 ++#define PMU7_PLL_CTL7_M4DIV_SHIFT 24 ++#define PMU7_PLL_CTL7_M4DIV_BY_6 6 ++#define PMU7_PLL_CTL7_M4DIV_BY_12 0xc ++#define PMU7_PLL_CTL7_M4DIV_BY_24 0x18 ++#define PMU7_PLL_PLLCTL8 8 ++#define PMU7_PLL_CTL8_M5DIV_MASK 0x000000ff ++#define PMU7_PLL_CTL8_M5DIV_SHIFT 0 ++#define PMU7_PLL_CTL8_M5DIV_BY_8 8 ++#define PMU7_PLL_CTL8_M5DIV_BY_12 0xc ++#define PMU7_PLL_CTL8_M5DIV_BY_24 0x18 ++#define PMU7_PLL_CTL8_M6DIV_MASK 0x0000ff00 ++#define PMU7_PLL_CTL8_M6DIV_SHIFT 8 ++#define PMU7_PLL_CTL8_M6DIV_BY_12 0xc ++#define PMU7_PLL_CTL8_M6DIV_BY_24 0x18 ++#define PMU7_PLL_PLLCTL11 11 ++#define PMU7_PLL_PLLCTL11_MASK 0xffffff00 ++#define PMU7_PLL_PLLCTL11_VAL 0x22222200 ++ ++/* PMU rev 15 */ ++#define PMU15_PLL_PLLCTL0 0 ++#define PMU15_PLL_PC0_CLKSEL_MASK 0x00000003 ++#define PMU15_PLL_PC0_CLKSEL_SHIFT 0 ++#define PMU15_PLL_PC0_FREQTGT_MASK 0x003FFFFC ++#define PMU15_PLL_PC0_FREQTGT_SHIFT 2 ++#define PMU15_PLL_PC0_PRESCALE_MASK 0x00C00000 ++#define PMU15_PLL_PC0_PRESCALE_SHIFT 22 ++#define PMU15_PLL_PC0_KPCTRL_MASK 0x07000000 ++#define PMU15_PLL_PC0_KPCTRL_SHIFT 24 ++#define PMU15_PLL_PC0_FCNTCTRL_MASK 0x38000000 ++#define PMU15_PLL_PC0_FCNTCTRL_SHIFT 27 ++#define PMU15_PLL_PC0_FDCMODE_MASK 0x40000000 ++#define PMU15_PLL_PC0_FDCMODE_SHIFT 30 ++#define PMU15_PLL_PC0_CTRLBIAS_MASK 0x80000000 ++#define PMU15_PLL_PC0_CTRLBIAS_SHIFT 31 ++ ++#define PMU15_PLL_PLLCTL1 1 ++#define PMU15_PLL_PC1_BIAS_CTLM_MASK 0x00000060 ++#define PMU15_PLL_PC1_BIAS_CTLM_SHIFT 5 ++#define PMU15_PLL_PC1_BIAS_CTLM_RST_MASK 0x00000040 ++#define PMU15_PLL_PC1_BIAS_CTLM_RST_SHIFT 6 ++#define PMU15_PLL_PC1_BIAS_SS_DIVR_MASK 0x0001FF80 ++#define PMU15_PLL_PC1_BIAS_SS_DIVR_SHIFT 7 ++#define PMU15_PLL_PC1_BIAS_SS_RSTVAL_MASK 0x03FE0000 ++#define PMU15_PLL_PC1_BIAS_SS_RSTVAL_SHIFT 17 ++#define PMU15_PLL_PC1_BIAS_INTG_BW_MASK 0x0C000000 ++#define PMU15_PLL_PC1_BIAS_INTG_BW_SHIFT 26 ++#define PMU15_PLL_PC1_BIAS_INTG_BYP_MASK 0x10000000 ++#define PMU15_PLL_PC1_BIAS_INTG_BYP_SHIFT 28 ++#define PMU15_PLL_PC1_OPENLP_EN_MASK 0x40000000 ++#define PMU15_PLL_PC1_OPENLP_EN_SHIFT 30 ++ ++#define PMU15_PLL_PLLCTL2 2 ++#define PMU15_PLL_PC2_CTEN_MASK 0x00000001 ++#define PMU15_PLL_PC2_CTEN_SHIFT 0 ++ ++#define PMU15_PLL_PLLCTL3 3 ++#define PMU15_PLL_PC3_DITHER_EN_MASK 0x00000001 ++#define PMU15_PLL_PC3_DITHER_EN_SHIFT 0 ++#define PMU15_PLL_PC3_DCOCTLSP_MASK 0xFE000000 ++#define PMU15_PLL_PC3_DCOCTLSP_SHIFT 25 ++#define PMU15_PLL_PC3_DCOCTLSP_DIV2EN_MASK 0x01 ++#define PMU15_PLL_PC3_DCOCTLSP_DIV2EN_SHIFT 0 ++#define PMU15_PLL_PC3_DCOCTLSP_CH0EN_MASK 0x02 ++#define PMU15_PLL_PC3_DCOCTLSP_CH0EN_SHIFT 1 ++#define PMU15_PLL_PC3_DCOCTLSP_CH1EN_MASK 0x04 ++#define PMU15_PLL_PC3_DCOCTLSP_CH1EN_SHIFT 2 ++#define PMU15_PLL_PC3_DCOCTLSP_CH0SEL_MASK 0x18 ++#define PMU15_PLL_PC3_DCOCTLSP_CH0SEL_SHIFT 3 ++#define PMU15_PLL_PC3_DCOCTLSP_CH1SEL_MASK 0x60 ++#define PMU15_PLL_PC3_DCOCTLSP_CH1SEL_SHIFT 5 ++#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV1 0 ++#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV2 1 ++#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV3 2 ++#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV5 3 ++ ++#define PMU15_PLL_PLLCTL4 4 ++#define PMU15_PLL_PC4_FLLCLK1_DIV_MASK 0x00000007 ++#define PMU15_PLL_PC4_FLLCLK1_DIV_SHIFT 0 ++#define PMU15_PLL_PC4_FLLCLK2_DIV_MASK 0x00000038 ++#define PMU15_PLL_PC4_FLLCLK2_DIV_SHIFT 3 ++#define PMU15_PLL_PC4_FLLCLK3_DIV_MASK 0x000001C0 ++#define PMU15_PLL_PC4_FLLCLK3_DIV_SHIFT 6 ++#define PMU15_PLL_PC4_DBGMODE_MASK 0x00000E00 ++#define PMU15_PLL_PC4_DBGMODE_SHIFT 9 ++#define PMU15_PLL_PC4_FLL480_CTLSP_LK_MASK 0x00001000 ++#define PMU15_PLL_PC4_FLL480_CTLSP_LK_SHIFT 12 ++#define PMU15_PLL_PC4_FLL480_CTLSP_MASK 0x000FE000 ++#define PMU15_PLL_PC4_FLL480_CTLSP_SHIFT 13 ++#define PMU15_PLL_PC4_DINPOL_MASK 0x00100000 ++#define PMU15_PLL_PC4_DINPOL_SHIFT 20 ++#define PMU15_PLL_PC4_CLKOUT_PD_MASK 0x00200000 ++#define PMU15_PLL_PC4_CLKOUT_PD_SHIFT 21 ++#define PMU15_PLL_PC4_CLKDIV2_PD_MASK 0x00400000 ++#define PMU15_PLL_PC4_CLKDIV2_PD_SHIFT 22 ++#define PMU15_PLL_PC4_CLKDIV4_PD_MASK 0x00800000 ++#define PMU15_PLL_PC4_CLKDIV4_PD_SHIFT 23 ++#define PMU15_PLL_PC4_CLKDIV8_PD_MASK 0x01000000 ++#define PMU15_PLL_PC4_CLKDIV8_PD_SHIFT 24 ++#define PMU15_PLL_PC4_CLKDIV16_PD_MASK 0x02000000 ++#define PMU15_PLL_PC4_CLKDIV16_PD_SHIFT 25 ++#define PMU15_PLL_PC4_TEST_EN_MASK 0x04000000 ++#define PMU15_PLL_PC4_TEST_EN_SHIFT 26 ++ ++#define PMU15_PLL_PLLCTL5 5 ++#define PMU15_PLL_PC5_FREQTGT_MASK 0x000FFFFF ++#define PMU15_PLL_PC5_FREQTGT_SHIFT 0 ++#define PMU15_PLL_PC5_DCOCTLSP_MASK 0x07F00000 ++#define PMU15_PLL_PC5_DCOCTLSP_SHIFT 20 ++#define PMU15_PLL_PC5_PRESCALE_MASK 0x18000000 ++#define PMU15_PLL_PC5_PRESCALE_SHIFT 27 ++ ++#define PMU15_PLL_PLLCTL6 6 ++#define PMU15_PLL_PC6_FREQTGT_MASK 0x000FFFFF ++#define PMU15_PLL_PC6_FREQTGT_SHIFT 0 ++#define PMU15_PLL_PC6_DCOCTLSP_MASK 0x07F00000 ++#define PMU15_PLL_PC6_DCOCTLSP_SHIFT 20 ++#define PMU15_PLL_PC6_PRESCALE_MASK 0x18000000 ++#define PMU15_PLL_PC6_PRESCALE_SHIFT 27 ++ ++#define PMU15_FREQTGT_480_DEFAULT 0x19AB1 ++#define PMU15_FREQTGT_492_DEFAULT 0x1A4F5 ++#define PMU15_ARM_96MHZ 96000000 /* 96 Mhz */ ++#define PMU15_ARM_98MHZ 98400000 /* 98.4 Mhz */ ++#define PMU15_ARM_97MHZ 97000000 /* 97 Mhz */ ++ ++ ++#define PMU17_PLLCTL2_NDIVTYPE_MASK 0x00000070 ++#define PMU17_PLLCTL2_NDIVTYPE_SHIFT 4 ++ ++#define PMU17_PLLCTL2_NDIV_MODE_INT 0 ++#define PMU17_PLLCTL2_NDIV_MODE_INT1B8 1 ++#define PMU17_PLLCTL2_NDIV_MODE_MASH111 2 ++#define PMU17_PLLCTL2_NDIV_MODE_MASH111B8 3 ++ ++#define PMU17_PLLCTL0_BBPLL_PWRDWN 0 ++#define PMU17_PLLCTL0_BBPLL_DRST 3 ++#define PMU17_PLLCTL0_BBPLL_DISBL_CLK 8 ++ ++/* PLL usage in 4716/47162 */ ++#define PMU4716_MAINPLL_PLL0 12 ++ ++/* PLL usage in 5356/5357 */ ++#define PMU5356_MAINPLL_PLL0 0 ++#define PMU5357_MAINPLL_PLL0 0 ++ ++/* 4716/47162 resources */ ++#define RES4716_PROC_PLL_ON 0x00000040 ++#define RES4716_PROC_HT_AVAIL 0x00000080 ++ ++/* 4716/4717/4718 Chip specific ChipControl register bits */ ++#define CCTRL_471X_I2S_PINS_ENABLE 0x0080 /* I2S pins off by default, shared w/ pflash */ ++ ++/* 5357 Chip specific ChipControl register bits */ ++/* 2nd - 32-bit reg */ ++#define CCTRL_5357_I2S_PINS_ENABLE 0x00040000 /* I2S pins enable */ ++#define CCTRL_5357_I2CSPI_PINS_ENABLE 0x00080000 /* I2C/SPI pins enable */ ++ ++/* 5354 resources */ ++#define RES5354_EXT_SWITCHER_PWM 0 /* 0x00001 */ ++#define RES5354_BB_SWITCHER_PWM 1 /* 0x00002 */ ++#define RES5354_BB_SWITCHER_BURST 2 /* 0x00004 */ ++#define RES5354_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */ ++#define RES5354_ILP_REQUEST 4 /* 0x00010 */ ++#define RES5354_RADIO_SWITCHER_PWM 5 /* 0x00020 */ ++#define RES5354_RADIO_SWITCHER_BURST 6 /* 0x00040 */ ++#define RES5354_ROM_SWITCH 7 /* 0x00080 */ ++#define RES5354_PA_REF_LDO 8 /* 0x00100 */ ++#define RES5354_RADIO_LDO 9 /* 0x00200 */ ++#define RES5354_AFE_LDO 10 /* 0x00400 */ ++#define RES5354_PLL_LDO 11 /* 0x00800 */ ++#define RES5354_BG_FILTBYP 12 /* 0x01000 */ ++#define RES5354_TX_FILTBYP 13 /* 0x02000 */ ++#define RES5354_RX_FILTBYP 14 /* 0x04000 */ ++#define RES5354_XTAL_PU 15 /* 0x08000 */ ++#define RES5354_XTAL_EN 16 /* 0x10000 */ ++#define RES5354_BB_PLL_FILTBYP 17 /* 0x20000 */ ++#define RES5354_RF_PLL_FILTBYP 18 /* 0x40000 */ ++#define RES5354_BB_PLL_PU 19 /* 0x80000 */ ++ ++/* 5357 Chip specific ChipControl register bits */ ++#define CCTRL5357_EXTPA (1<<14) /* extPA in ChipControl 1, bit 14 */ ++#define CCTRL5357_ANT_MUX_2o3 (1<<15) /* 2o3 in ChipControl 1, bit 15 */ ++#define CCTRL5357_NFLASH (1<<16) /* Nandflash in ChipControl 1, bit 16 */ ++ ++/* 43217 Chip specific ChipControl register bits */ ++#define CCTRL43217_EXTPA_C0 (1<<13) /* core0 extPA in ChipControl 1, bit 13 */ ++#define CCTRL43217_EXTPA_C1 (1<<8) /* core1 extPA in ChipControl 1, bit 8 */ ++ ++/* 4328 resources */ ++#define RES4328_EXT_SWITCHER_PWM 0 /* 0x00001 */ ++#define RES4328_BB_SWITCHER_PWM 1 /* 0x00002 */ ++#define RES4328_BB_SWITCHER_BURST 2 /* 0x00004 */ ++#define RES4328_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */ ++#define RES4328_ILP_REQUEST 4 /* 0x00010 */ ++#define RES4328_RADIO_SWITCHER_PWM 5 /* 0x00020 */ ++#define RES4328_RADIO_SWITCHER_BURST 6 /* 0x00040 */ ++#define RES4328_ROM_SWITCH 7 /* 0x00080 */ ++#define RES4328_PA_REF_LDO 8 /* 0x00100 */ ++#define RES4328_RADIO_LDO 9 /* 0x00200 */ ++#define RES4328_AFE_LDO 10 /* 0x00400 */ ++#define RES4328_PLL_LDO 11 /* 0x00800 */ ++#define RES4328_BG_FILTBYP 12 /* 0x01000 */ ++#define RES4328_TX_FILTBYP 13 /* 0x02000 */ ++#define RES4328_RX_FILTBYP 14 /* 0x04000 */ ++#define RES4328_XTAL_PU 15 /* 0x08000 */ ++#define RES4328_XTAL_EN 16 /* 0x10000 */ ++#define RES4328_BB_PLL_FILTBYP 17 /* 0x20000 */ ++#define RES4328_RF_PLL_FILTBYP 18 /* 0x40000 */ ++#define RES4328_BB_PLL_PU 19 /* 0x80000 */ ++ ++/* 4325 A0/A1 resources */ ++#define RES4325_BUCK_BOOST_BURST 0 /* 0x00000001 */ ++#define RES4325_CBUCK_BURST 1 /* 0x00000002 */ ++#define RES4325_CBUCK_PWM 2 /* 0x00000004 */ ++#define RES4325_CLDO_CBUCK_BURST 3 /* 0x00000008 */ ++#define RES4325_CLDO_CBUCK_PWM 4 /* 0x00000010 */ ++#define RES4325_BUCK_BOOST_PWM 5 /* 0x00000020 */ ++#define RES4325_ILP_REQUEST 6 /* 0x00000040 */ ++#define RES4325_ABUCK_BURST 7 /* 0x00000080 */ ++#define RES4325_ABUCK_PWM 8 /* 0x00000100 */ ++#define RES4325_LNLDO1_PU 9 /* 0x00000200 */ ++#define RES4325_OTP_PU 10 /* 0x00000400 */ ++#define RES4325_LNLDO3_PU 11 /* 0x00000800 */ ++#define RES4325_LNLDO4_PU 12 /* 0x00001000 */ ++#define RES4325_XTAL_PU 13 /* 0x00002000 */ ++#define RES4325_ALP_AVAIL 14 /* 0x00004000 */ ++#define RES4325_RX_PWRSW_PU 15 /* 0x00008000 */ ++#define RES4325_TX_PWRSW_PU 16 /* 0x00010000 */ ++#define RES4325_RFPLL_PWRSW_PU 17 /* 0x00020000 */ ++#define RES4325_LOGEN_PWRSW_PU 18 /* 0x00040000 */ ++#define RES4325_AFE_PWRSW_PU 19 /* 0x00080000 */ ++#define RES4325_BBPLL_PWRSW_PU 20 /* 0x00100000 */ ++#define RES4325_HT_AVAIL 21 /* 0x00200000 */ ++ ++/* 4325 B0/C0 resources */ ++#define RES4325B0_CBUCK_LPOM 1 /* 0x00000002 */ ++#define RES4325B0_CBUCK_BURST 2 /* 0x00000004 */ ++#define RES4325B0_CBUCK_PWM 3 /* 0x00000008 */ ++#define RES4325B0_CLDO_PU 4 /* 0x00000010 */ ++ ++/* 4325 C1 resources */ ++#define RES4325C1_LNLDO2_PU 12 /* 0x00001000 */ ++ ++/* 4325 chip-specific ChipStatus register bits */ ++#define CST4325_SPROM_OTP_SEL_MASK 0x00000003 ++#define CST4325_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ ++#define CST4325_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ ++#define CST4325_OTP_SEL 2 /* OTP is powered up, no SPROM */ ++#define CST4325_OTP_PWRDN 3 /* OTP is powered down, SPROM is present */ ++#define CST4325_SDIO_USB_MODE_MASK 0x00000004 ++#define CST4325_SDIO_USB_MODE_SHIFT 2 ++#define CST4325_RCAL_VALID_MASK 0x00000008 ++#define CST4325_RCAL_VALID_SHIFT 3 ++#define CST4325_RCAL_VALUE_MASK 0x000001f0 ++#define CST4325_RCAL_VALUE_SHIFT 4 ++#define CST4325_PMUTOP_2B_MASK 0x00000200 /* 1 for 2b, 0 for to 2a */ ++#define CST4325_PMUTOP_2B_SHIFT 9 ++ ++#define RES4329_RESERVED0 0 /* 0x00000001 */ ++#define RES4329_CBUCK_LPOM 1 /* 0x00000002 */ ++#define RES4329_CBUCK_BURST 2 /* 0x00000004 */ ++#define RES4329_CBUCK_PWM 3 /* 0x00000008 */ ++#define RES4329_CLDO_PU 4 /* 0x00000010 */ ++#define RES4329_PALDO_PU 5 /* 0x00000020 */ ++#define RES4329_ILP_REQUEST 6 /* 0x00000040 */ ++#define RES4329_RESERVED7 7 /* 0x00000080 */ ++#define RES4329_RESERVED8 8 /* 0x00000100 */ ++#define RES4329_LNLDO1_PU 9 /* 0x00000200 */ ++#define RES4329_OTP_PU 10 /* 0x00000400 */ ++#define RES4329_RESERVED11 11 /* 0x00000800 */ ++#define RES4329_LNLDO2_PU 12 /* 0x00001000 */ ++#define RES4329_XTAL_PU 13 /* 0x00002000 */ ++#define RES4329_ALP_AVAIL 14 /* 0x00004000 */ ++#define RES4329_RX_PWRSW_PU 15 /* 0x00008000 */ ++#define RES4329_TX_PWRSW_PU 16 /* 0x00010000 */ ++#define RES4329_RFPLL_PWRSW_PU 17 /* 0x00020000 */ ++#define RES4329_LOGEN_PWRSW_PU 18 /* 0x00040000 */ ++#define RES4329_AFE_PWRSW_PU 19 /* 0x00080000 */ ++#define RES4329_BBPLL_PWRSW_PU 20 /* 0x00100000 */ ++#define RES4329_HT_AVAIL 21 /* 0x00200000 */ ++ ++#define CST4329_SPROM_OTP_SEL_MASK 0x00000003 ++#define CST4329_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ ++#define CST4329_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ ++#define CST4329_OTP_SEL 2 /* OTP is powered up, no SPROM */ ++#define CST4329_OTP_PWRDN 3 /* OTP is powered down, SPROM is present */ ++#define CST4329_SPI_SDIO_MODE_MASK 0x00000004 ++#define CST4329_SPI_SDIO_MODE_SHIFT 2 ++ ++/* 4312 chip-specific ChipStatus register bits */ ++#define CST4312_SPROM_OTP_SEL_MASK 0x00000003 ++#define CST4312_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */ ++#define CST4312_SPROM_SEL 1 /* OTP is powered up, SPROM is present */ ++#define CST4312_OTP_SEL 2 /* OTP is powered up, no SPROM */ ++#define CST4312_OTP_BAD 3 /* OTP is broken, SPROM is present */ ++ ++/* 4312 resources (all PMU chips with little memory constraint) */ ++#define RES4312_SWITCHER_BURST 0 /* 0x00000001 */ ++#define RES4312_SWITCHER_PWM 1 /* 0x00000002 */ ++#define RES4312_PA_REF_LDO 2 /* 0x00000004 */ ++#define RES4312_CORE_LDO_BURST 3 /* 0x00000008 */ ++#define RES4312_CORE_LDO_PWM 4 /* 0x00000010 */ ++#define RES4312_RADIO_LDO 5 /* 0x00000020 */ ++#define RES4312_ILP_REQUEST 6 /* 0x00000040 */ ++#define RES4312_BG_FILTBYP 7 /* 0x00000080 */ ++#define RES4312_TX_FILTBYP 8 /* 0x00000100 */ ++#define RES4312_RX_FILTBYP 9 /* 0x00000200 */ ++#define RES4312_XTAL_PU 10 /* 0x00000400 */ ++#define RES4312_ALP_AVAIL 11 /* 0x00000800 */ ++#define RES4312_BB_PLL_FILTBYP 12 /* 0x00001000 */ ++#define RES4312_RF_PLL_FILTBYP 13 /* 0x00002000 */ ++#define RES4312_HT_AVAIL 14 /* 0x00004000 */ ++ ++/* 4322 resources */ ++#define RES4322_RF_LDO 0 ++#define RES4322_ILP_REQUEST 1 ++#define RES4322_XTAL_PU 2 ++#define RES4322_ALP_AVAIL 3 ++#define RES4322_SI_PLL_ON 4 ++#define RES4322_HT_SI_AVAIL 5 ++#define RES4322_PHY_PLL_ON 6 ++#define RES4322_HT_PHY_AVAIL 7 ++#define RES4322_OTP_PU 8 ++ ++/* 4322 chip-specific ChipStatus register bits */ ++#define CST4322_XTAL_FREQ_20_40MHZ 0x00000020 ++#define CST4322_SPROM_OTP_SEL_MASK 0x000000c0 ++#define CST4322_SPROM_OTP_SEL_SHIFT 6 ++#define CST4322_NO_SPROM_OTP 0 /* no OTP, no SPROM */ ++#define CST4322_SPROM_PRESENT 1 /* SPROM is present */ ++#define CST4322_OTP_PRESENT 2 /* OTP is present */ ++#define CST4322_PCI_OR_USB 0x00000100 ++#define CST4322_BOOT_MASK 0x00000600 ++#define CST4322_BOOT_SHIFT 9 ++#define CST4322_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ ++#define CST4322_BOOT_FROM_ROM 1 /* boot from ROM */ ++#define CST4322_BOOT_FROM_FLASH 2 /* boot from FLASH */ ++#define CST4322_BOOT_FROM_INVALID 3 ++#define CST4322_ILP_DIV_EN 0x00000800 ++#define CST4322_FLASH_TYPE_MASK 0x00001000 ++#define CST4322_FLASH_TYPE_SHIFT 12 ++#define CST4322_FLASH_TYPE_SHIFT_ST 0 /* ST serial FLASH */ ++#define CST4322_FLASH_TYPE_SHIFT_ATMEL 1 /* ATMEL flash */ ++#define CST4322_ARM_TAP_SEL 0x00002000 ++#define CST4322_RES_INIT_MODE_MASK 0x0000c000 ++#define CST4322_RES_INIT_MODE_SHIFT 14 ++#define CST4322_RES_INIT_MODE_ILPAVAIL 0 /* resinitmode: ILP available */ ++#define CST4322_RES_INIT_MODE_ILPREQ 1 /* resinitmode: ILP request */ ++#define CST4322_RES_INIT_MODE_ALPAVAIL 2 /* resinitmode: ALP available */ ++#define CST4322_RES_INIT_MODE_HTAVAIL 3 /* resinitmode: HT available */ ++#define CST4322_PCIPLLCLK_GATING 0x00010000 ++#define CST4322_CLK_SWITCH_PCI_TO_ALP 0x00020000 ++#define CST4322_PCI_CARDBUS_MODE 0x00040000 ++ ++/* 43224 chip-specific ChipControl register bits */ ++#define CCTRL43224_GPIO_TOGGLE 0x8000 /* gpio[3:0] pins as btcoex or s/w gpio */ ++#define CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 /* 12 mA drive strength */ ++#define CCTRL_43224B0_12MA_LED_DRIVE 0xF0 /* 12 mA drive strength for later 43224s */ ++ ++/* 43236 resources */ ++#define RES43236_REGULATOR 0 ++#define RES43236_ILP_REQUEST 1 ++#define RES43236_XTAL_PU 2 ++#define RES43236_ALP_AVAIL 3 ++#define RES43236_SI_PLL_ON 4 ++#define RES43236_HT_SI_AVAIL 5 ++ ++/* 43236 chip-specific ChipControl register bits */ ++#define CCTRL43236_BT_COEXIST (1<<0) /* 0 disable */ ++#define CCTRL43236_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ ++#define CCTRL43236_EXT_LNA (1<<2) /* 0 disable */ ++#define CCTRL43236_ANT_MUX_2o3 (1<<3) /* 2o3 mux, chipcontrol bit 3 */ ++#define CCTRL43236_GSIO (1<<4) /* 0 disable */ ++ ++/* 43236 Chip specific ChipStatus register bits */ ++#define CST43236_SFLASH_MASK 0x00000040 ++#define CST43236_OTP_SEL_MASK 0x00000080 ++#define CST43236_OTP_SEL_SHIFT 7 ++#define CST43236_HSIC_MASK 0x00000100 /* USB/HSIC */ ++#define CST43236_BP_CLK 0x00000200 /* 120/96Mbps */ ++#define CST43236_BOOT_MASK 0x00001800 ++#define CST43236_BOOT_SHIFT 11 ++#define CST43236_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ ++#define CST43236_BOOT_FROM_ROM 1 /* boot from ROM */ ++#define CST43236_BOOT_FROM_FLASH 2 /* boot from FLASH */ ++#define CST43236_BOOT_FROM_INVALID 3 ++ ++/* 43237 resources */ ++#define RES43237_REGULATOR 0 ++#define RES43237_ILP_REQUEST 1 ++#define RES43237_XTAL_PU 2 ++#define RES43237_ALP_AVAIL 3 ++#define RES43237_SI_PLL_ON 4 ++#define RES43237_HT_SI_AVAIL 5 ++ ++/* 43237 chip-specific ChipControl register bits */ ++#define CCTRL43237_BT_COEXIST (1<<0) /* 0 disable */ ++#define CCTRL43237_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ ++#define CCTRL43237_EXT_LNA (1<<2) /* 0 disable */ ++#define CCTRL43237_ANT_MUX_2o3 (1<<3) /* 2o3 mux, chipcontrol bit 3 */ ++#define CCTRL43237_GSIO (1<<4) /* 0 disable */ ++ ++/* 43237 Chip specific ChipStatus register bits */ ++#define CST43237_SFLASH_MASK 0x00000040 ++#define CST43237_OTP_SEL_MASK 0x00000080 ++#define CST43237_OTP_SEL_SHIFT 7 ++#define CST43237_HSIC_MASK 0x00000100 /* USB/HSIC */ ++#define CST43237_BP_CLK 0x00000200 /* 120/96Mbps */ ++#define CST43237_BOOT_MASK 0x00001800 ++#define CST43237_BOOT_SHIFT 11 ++#define CST43237_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ ++#define CST43237_BOOT_FROM_ROM 1 /* boot from ROM */ ++#define CST43237_BOOT_FROM_FLASH 2 /* boot from FLASH */ ++#define CST43237_BOOT_FROM_INVALID 3 ++ ++/* 43239 resources */ ++#define RES43239_OTP_PU 9 ++#define RES43239_MACPHY_CLKAVAIL 23 ++#define RES43239_HT_AVAIL 24 ++ ++/* 43239 Chip specific ChipStatus register bits */ ++#define CST43239_SPROM_MASK 0x00000002 ++#define CST43239_SFLASH_MASK 0x00000004 ++#define CST43239_RES_INIT_MODE_SHIFT 7 ++#define CST43239_RES_INIT_MODE_MASK 0x000001f0 ++#define CST43239_CHIPMODE_SDIOD(cs) ((cs) & (1 << 15)) /* SDIO || gSPI */ ++#define CST43239_CHIPMODE_USB20D(cs) (~(cs) & (1 << 15)) /* USB || USBDA */ ++#define CST43239_CHIPMODE_SDIO(cs) (((cs) & (1 << 0)) == 0) /* SDIO */ ++#define CST43239_CHIPMODE_GSPI(cs) (((cs) & (1 << 0)) == (1 << 0)) /* gSPI */ ++ ++/* 4324 resources */ ++#define RES4324_OTP_PU 10 ++#define RES4324_HT_AVAIL 29 ++#define RES4324_MACPHY_CLKAVAIL 30 ++ ++/* 4324 Chip specific ChipStatus register bits */ ++#define CST4324_SPROM_MASK 0x00000080 ++#define CST4324_SFLASH_MASK 0x00400000 ++#define CST4324_RES_INIT_MODE_SHIFT 10 ++#define CST4324_RES_INIT_MODE_MASK 0x00000c00 ++#define CST4324_CHIPMODE_MASK 0x7 ++#define CST4324_CHIPMODE_SDIOD(cs) ((~(cs)) & (1 << 2)) /* SDIO || gSPI */ ++#define CST4324_CHIPMODE_USB20D(cs) (((cs) & CST4324_CHIPMODE_MASK) == 0x6) /* USB || USBDA */ ++ ++/* 4331 resources */ ++#define RES4331_REGULATOR 0 ++#define RES4331_ILP_REQUEST 1 ++#define RES4331_XTAL_PU 2 ++#define RES4331_ALP_AVAIL 3 ++#define RES4331_SI_PLL_ON 4 ++#define RES4331_HT_SI_AVAIL 5 ++ ++/* 4331 chip-specific ChipControl register bits */ ++#define CCTRL4331_BT_COEXIST (1<<0) /* 0 disable */ ++#define CCTRL4331_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ ++#define CCTRL4331_EXT_LNA_G (1<<2) /* 0 disable */ ++#define CCTRL4331_SPROM_GPIO13_15 (1<<3) /* sprom/gpio13-15 mux */ ++#define CCTRL4331_EXTPA_EN (1<<4) /* 0 ext pa disable, 1 ext pa enabled */ ++#define CCTRL4331_GPIOCLK_ON_SPROMCS (1<<5) /* set drive out GPIO_CLK on sprom_cs pin */ ++#define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6) /* use sprom_cs pin as PCIE mdio interface */ ++#define CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7) /* aband extpa will be at gpio2/5 and sprom_dout */ ++#define CCTRL4331_OVR_PIPEAUXCLKEN (1<<8) /* override core control on pipe_AuxClkEnable */ ++#define CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9) /* override core control on pipe_AuxPowerDown */ ++#define CCTRL4331_PCIE_AUXCLKEN (1<<10) /* pcie_auxclkenable */ ++#define CCTRL4331_PCIE_PIPE_PLLDOWN (1<<11) /* pcie_pipe_pllpowerdown */ ++#define CCTRL4331_EXTPA_EN2 (1<<12) /* 0 ext pa disable, 1 ext pa enabled */ ++#define CCTRL4331_EXT_LNA_A (1<<13) /* 0 disable */ ++#define CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16) /* enable bt_shd0 at gpio4 */ ++#define CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17) /* enable bt_shd1 at gpio5 */ ++#define CCTRL4331_EXTPA_ANA_EN (1<<24) /* 0 ext pa disable, 1 ext pa enabled */ ++ ++/* 4331 Chip specific ChipStatus register bits */ ++#define CST4331_XTAL_FREQ 0x00000001 /* crystal frequency 20/40Mhz */ ++#define CST4331_SPROM_OTP_SEL_MASK 0x00000006 ++#define CST4331_SPROM_OTP_SEL_SHIFT 1 ++#define CST4331_SPROM_PRESENT 0x00000002 ++#define CST4331_OTP_PRESENT 0x00000004 ++#define CST4331_LDO_RF 0x00000008 ++#define CST4331_LDO_PAR 0x00000010 ++ ++/* 4315 resource */ ++#define RES4315_CBUCK_LPOM 1 /* 0x00000002 */ ++#define RES4315_CBUCK_BURST 2 /* 0x00000004 */ ++#define RES4315_CBUCK_PWM 3 /* 0x00000008 */ ++#define RES4315_CLDO_PU 4 /* 0x00000010 */ ++#define RES4315_PALDO_PU 5 /* 0x00000020 */ ++#define RES4315_ILP_REQUEST 6 /* 0x00000040 */ ++#define RES4315_LNLDO1_PU 9 /* 0x00000200 */ ++#define RES4315_OTP_PU 10 /* 0x00000400 */ ++#define RES4315_LNLDO2_PU 12 /* 0x00001000 */ ++#define RES4315_XTAL_PU 13 /* 0x00002000 */ ++#define RES4315_ALP_AVAIL 14 /* 0x00004000 */ ++#define RES4315_RX_PWRSW_PU 15 /* 0x00008000 */ ++#define RES4315_TX_PWRSW_PU 16 /* 0x00010000 */ ++#define RES4315_RFPLL_PWRSW_PU 17 /* 0x00020000 */ ++#define RES4315_LOGEN_PWRSW_PU 18 /* 0x00040000 */ ++#define RES4315_AFE_PWRSW_PU 19 /* 0x00080000 */ ++#define RES4315_BBPLL_PWRSW_PU 20 /* 0x00100000 */ ++#define RES4315_HT_AVAIL 21 /* 0x00200000 */ ++ ++/* 4315 chip-specific ChipStatus register bits */ ++#define CST4315_SPROM_OTP_SEL_MASK 0x00000003 /* gpio [7:6], SDIO CIS selection */ ++#define CST4315_DEFCIS_SEL 0x00000000 /* use default CIS, OTP is powered up */ ++#define CST4315_SPROM_SEL 0x00000001 /* use SPROM, OTP is powered up */ ++#define CST4315_OTP_SEL 0x00000002 /* use OTP, OTP is powered up */ ++#define CST4315_OTP_PWRDN 0x00000003 /* use SPROM, OTP is powered down */ ++#define CST4315_SDIO_MODE 0x00000004 /* gpio [8], sdio/usb mode */ ++#define CST4315_RCAL_VALID 0x00000008 ++#define CST4315_RCAL_VALUE_MASK 0x000001f0 ++#define CST4315_RCAL_VALUE_SHIFT 4 ++#define CST4315_PALDO_EXTPNP 0x00000200 /* PALDO is configured with external PNP */ ++#define CST4315_CBUCK_MODE_MASK 0x00000c00 ++#define CST4315_CBUCK_MODE_BURST 0x00000400 ++#define CST4315_CBUCK_MODE_LPBURST 0x00000c00 ++ ++/* 4319 resources */ ++#define RES4319_CBUCK_LPOM 1 /* 0x00000002 */ ++#define RES4319_CBUCK_BURST 2 /* 0x00000004 */ ++#define RES4319_CBUCK_PWM 3 /* 0x00000008 */ ++#define RES4319_CLDO_PU 4 /* 0x00000010 */ ++#define RES4319_PALDO_PU 5 /* 0x00000020 */ ++#define RES4319_ILP_REQUEST 6 /* 0x00000040 */ ++#define RES4319_LNLDO1_PU 9 /* 0x00000200 */ ++#define RES4319_OTP_PU 10 /* 0x00000400 */ ++#define RES4319_LNLDO2_PU 12 /* 0x00001000 */ ++#define RES4319_XTAL_PU 13 /* 0x00002000 */ ++#define RES4319_ALP_AVAIL 14 /* 0x00004000 */ ++#define RES4319_RX_PWRSW_PU 15 /* 0x00008000 */ ++#define RES4319_TX_PWRSW_PU 16 /* 0x00010000 */ ++#define RES4319_RFPLL_PWRSW_PU 17 /* 0x00020000 */ ++#define RES4319_LOGEN_PWRSW_PU 18 /* 0x00040000 */ ++#define RES4319_AFE_PWRSW_PU 19 /* 0x00080000 */ ++#define RES4319_BBPLL_PWRSW_PU 20 /* 0x00100000 */ ++#define RES4319_HT_AVAIL 21 /* 0x00200000 */ ++ ++/* 4319 chip-specific ChipStatus register bits */ ++#define CST4319_SPI_CPULESSUSB 0x00000001 ++#define CST4319_SPI_CLK_POL 0x00000002 ++#define CST4319_SPI_CLK_PH 0x00000008 ++#define CST4319_SPROM_OTP_SEL_MASK 0x000000c0 /* gpio [7:6], SDIO CIS selection */ ++#define CST4319_SPROM_OTP_SEL_SHIFT 6 ++#define CST4319_DEFCIS_SEL 0x00000000 /* use default CIS, OTP is powered up */ ++#define CST4319_SPROM_SEL 0x00000040 /* use SPROM, OTP is powered up */ ++#define CST4319_OTP_SEL 0x00000080 /* use OTP, OTP is powered up */ ++#define CST4319_OTP_PWRDN 0x000000c0 /* use SPROM, OTP is powered down */ ++#define CST4319_SDIO_USB_MODE 0x00000100 /* gpio [8], sdio/usb mode */ ++#define CST4319_REMAP_SEL_MASK 0x00000600 ++#define CST4319_ILPDIV_EN 0x00000800 ++#define CST4319_XTAL_PD_POL 0x00001000 ++#define CST4319_LPO_SEL 0x00002000 ++#define CST4319_RES_INIT_MODE 0x0000c000 ++#define CST4319_PALDO_EXTPNP 0x00010000 /* PALDO is configured with external PNP */ ++#define CST4319_CBUCK_MODE_MASK 0x00060000 ++#define CST4319_CBUCK_MODE_BURST 0x00020000 ++#define CST4319_CBUCK_MODE_LPBURST 0x00060000 ++#define CST4319_RCAL_VALID 0x01000000 ++#define CST4319_RCAL_VALUE_MASK 0x3e000000 ++#define CST4319_RCAL_VALUE_SHIFT 25 ++ ++#define PMU1_PLL0_CHIPCTL0 0 ++#define PMU1_PLL0_CHIPCTL1 1 ++#define PMU1_PLL0_CHIPCTL2 2 ++#define CCTL_4319USB_XTAL_SEL_MASK 0x00180000 ++#define CCTL_4319USB_XTAL_SEL_SHIFT 19 ++#define CCTL_4319USB_48MHZ_PLL_SEL 1 ++#define CCTL_4319USB_24MHZ_PLL_SEL 2 ++ ++/* PMU resources for 4336 */ ++#define RES4336_CBUCK_LPOM 0 ++#define RES4336_CBUCK_BURST 1 ++#define RES4336_CBUCK_LP_PWM 2 ++#define RES4336_CBUCK_PWM 3 ++#define RES4336_CLDO_PU 4 ++#define RES4336_DIS_INT_RESET_PD 5 ++#define RES4336_ILP_REQUEST 6 ++#define RES4336_LNLDO_PU 7 ++#define RES4336_LDO3P3_PU 8 ++#define RES4336_OTP_PU 9 ++#define RES4336_XTAL_PU 10 ++#define RES4336_ALP_AVAIL 11 ++#define RES4336_RADIO_PU 12 ++#define RES4336_BG_PU 13 ++#define RES4336_VREG1p4_PU_PU 14 ++#define RES4336_AFE_PWRSW_PU 15 ++#define RES4336_RX_PWRSW_PU 16 ++#define RES4336_TX_PWRSW_PU 17 ++#define RES4336_BB_PWRSW_PU 18 ++#define RES4336_SYNTH_PWRSW_PU 19 ++#define RES4336_MISC_PWRSW_PU 20 ++#define RES4336_LOGEN_PWRSW_PU 21 ++#define RES4336_BBPLL_PWRSW_PU 22 ++#define RES4336_MACPHY_CLKAVAIL 23 ++#define RES4336_HT_AVAIL 24 ++#define RES4336_RSVD 25 ++ ++/* 4336 chip-specific ChipStatus register bits */ ++#define CST4336_SPI_MODE_MASK 0x00000001 ++#define CST4336_SPROM_PRESENT 0x00000002 ++#define CST4336_OTP_PRESENT 0x00000004 ++#define CST4336_ARMREMAP_0 0x00000008 ++#define CST4336_ILPDIV_EN_MASK 0x00000010 ++#define CST4336_ILPDIV_EN_SHIFT 4 ++#define CST4336_XTAL_PD_POL_MASK 0x00000020 ++#define CST4336_XTAL_PD_POL_SHIFT 5 ++#define CST4336_LPO_SEL_MASK 0x00000040 ++#define CST4336_LPO_SEL_SHIFT 6 ++#define CST4336_RES_INIT_MODE_MASK 0x00000180 ++#define CST4336_RES_INIT_MODE_SHIFT 7 ++#define CST4336_CBUCK_MODE_MASK 0x00000600 ++#define CST4336_CBUCK_MODE_SHIFT 9 ++ ++/* 4336 Chip specific PMU ChipControl register bits */ ++#define PCTL_4336_SERIAL_ENAB (1 << 24) ++ ++/* 4330 resources */ ++#define RES4330_CBUCK_LPOM 0 ++#define RES4330_CBUCK_BURST 1 ++#define RES4330_CBUCK_LP_PWM 2 ++#define RES4330_CBUCK_PWM 3 ++#define RES4330_CLDO_PU 4 ++#define RES4330_DIS_INT_RESET_PD 5 ++#define RES4330_ILP_REQUEST 6 ++#define RES4330_LNLDO_PU 7 ++#define RES4330_LDO3P3_PU 8 ++#define RES4330_OTP_PU 9 ++#define RES4330_XTAL_PU 10 ++#define RES4330_ALP_AVAIL 11 ++#define RES4330_RADIO_PU 12 ++#define RES4330_BG_PU 13 ++#define RES4330_VREG1p4_PU_PU 14 ++#define RES4330_AFE_PWRSW_PU 15 ++#define RES4330_RX_PWRSW_PU 16 ++#define RES4330_TX_PWRSW_PU 17 ++#define RES4330_BB_PWRSW_PU 18 ++#define RES4330_SYNTH_PWRSW_PU 19 ++#define RES4330_MISC_PWRSW_PU 20 ++#define RES4330_LOGEN_PWRSW_PU 21 ++#define RES4330_BBPLL_PWRSW_PU 22 ++#define RES4330_MACPHY_CLKAVAIL 23 ++#define RES4330_HT_AVAIL 24 ++#define RES4330_5gRX_PWRSW_PU 25 ++#define RES4330_5gTX_PWRSW_PU 26 ++#define RES4330_5g_LOGEN_PWRSW_PU 27 ++ ++/* 4330 chip-specific ChipStatus register bits */ ++#define CST4330_CHIPMODE_SDIOD(cs) (((cs) & 0x7) < 6) /* SDIO || gSPI */ ++#define CST4330_CHIPMODE_USB20D(cs) (((cs) & 0x7) >= 6) /* USB || USBDA */ ++#define CST4330_CHIPMODE_SDIO(cs) (((cs) & 0x4) == 0) /* SDIO */ ++#define CST4330_CHIPMODE_GSPI(cs) (((cs) & 0x6) == 4) /* gSPI */ ++#define CST4330_CHIPMODE_USB(cs) (((cs) & 0x7) == 6) /* USB packet-oriented */ ++#define CST4330_CHIPMODE_USBDA(cs) (((cs) & 0x7) == 7) /* USB Direct Access */ ++#define CST4330_OTP_PRESENT 0x00000010 ++#define CST4330_LPO_AUTODET_EN 0x00000020 ++#define CST4330_ARMREMAP_0 0x00000040 ++#define CST4330_SPROM_PRESENT 0x00000080 /* takes priority over OTP if both set */ ++#define CST4330_ILPDIV_EN 0x00000100 ++#define CST4330_LPO_SEL 0x00000200 ++#define CST4330_RES_INIT_MODE_SHIFT 10 ++#define CST4330_RES_INIT_MODE_MASK 0x00000c00 ++#define CST4330_CBUCK_MODE_SHIFT 12 ++#define CST4330_CBUCK_MODE_MASK 0x00003000 ++#define CST4330_CBUCK_POWER_OK 0x00004000 ++#define CST4330_BB_PLL_LOCKED 0x00008000 ++#define SOCDEVRAM_BP_ADDR 0x1E000000 ++#define SOCDEVRAM_ARM_ADDR 0x00800000 ++ ++/* 4330 Chip specific PMU ChipControl register bits */ ++#define PCTL_4330_SERIAL_ENAB (1 << 24) ++ ++/* 4330 Chip specific ChipControl register bits */ ++#define CCTRL_4330_GPIO_SEL 0x00000001 /* 1=select GPIOs to be muxed out */ ++#define CCTRL_4330_ERCX_SEL 0x00000002 /* 1=select ERCX BT coex to be muxed out */ ++#define CCTRL_4330_SDIO_HOST_WAKE 0x00000004 /* SDIO: 1=configure GPIO0 for host wake */ ++#define CCTRL_4330_JTAG_DISABLE 0x00000008 /* 1=disable JTAG interface on mux'd pins */ ++ ++#define PMU_VREG0_ADDR 0 ++#define PMU_VREG0_DISABLE_PULLD_BT_SHIFT 2 ++#define PMU_VREG0_DISABLE_PULLD_WL_SHIFT 3 ++ ++/* 4334 resources */ ++#define RES4334_LPLDO_PU 0 ++#define RES4334_RESET_PULLDN_DIS 1 ++#define RES4334_PMU_BG_PU 2 ++#define RES4334_HSIC_LDO_PU 3 ++#define RES4334_CBUCK_LPOM_PU 4 ++#define RES4334_CBUCK_PFM_PU 5 ++#define RES4334_CLDO_PU 6 ++#define RES4334_LPLDO2_LVM 7 ++#define RES4334_LNLDO_PU 8 ++#define RES4334_LDO3P3_PU 9 ++#define RES4334_OTP_PU 10 ++#define RES4334_XTAL_PU 11 ++#define RES4334_WL_PWRSW_PU 12 ++#define RES4334_LQ_AVAIL 13 ++#define RES4334_LOGIC_RET 14 ++#define RES4334_MEM_SLEEP 15 ++#define RES4334_MACPHY_RET 16 ++#define RES4334_WL_CORE_READY 17 ++#define RES4334_ILP_REQ 18 ++#define RES4334_ALP_AVAIL 19 ++#define RES4334_MISC_PWRSW_PU 20 ++#define RES4334_SYNTH_PWRSW_PU 21 ++#define RES4334_RX_PWRSW_PU 22 ++#define RES4334_RADIO_PU 23 ++#define RES4334_WL_PMU_PU 24 ++#define RES4334_VCO_LDO_PU 25 ++#define RES4334_AFE_LDO_PU 26 ++#define RES4334_RX_LDO_PU 27 ++#define RES4334_TX_LDO_PU 28 ++#define RES4334_HT_AVAIL 29 ++#define RES4334_MACPHY_CLK_AVAIL 30 ++ ++/* 4334 chip-specific ChipStatus register bits */ ++#define CST4334_CHIPMODE_MASK 7 ++#define CST4334_SDIO_MODE 0x00000000 ++#define CST4334_SPI_MODE 0x00000004 ++#define CST4334_HSIC_MODE 0x00000006 ++#define CST4334_BLUSB_MODE 0x00000007 ++#define CST4334_CHIPMODE_HSIC(cs) (((cs) & CST4334_CHIPMODE_MASK) == CST4334_HSIC_MODE) ++#define CST4334_OTP_PRESENT 0x00000010 ++#define CST4334_LPO_AUTODET_EN 0x00000020 ++#define CST4334_ARMREMAP_0 0x00000040 ++#define CST4334_SPROM_PRESENT 0x00000080 ++#define CST4334_ILPDIV_EN_MASK 0x00000100 ++#define CST4334_ILPDIV_EN_SHIFT 8 ++#define CST4334_LPO_SEL_MASK 0x00000200 ++#define CST4334_LPO_SEL_SHIFT 9 ++#define CST4334_RES_INIT_MODE_MASK 0x00000C00 ++#define CST4334_RES_INIT_MODE_SHIFT 10 ++ ++/* 4334 Chip specific PMU ChipControl register bits */ ++#define PCTL_4334_GPIO3_ENAB (1 << 3) ++ ++/* 4334 Chip control */ ++#define CCTRL4334_HSIC_LDO_PU (1 << 23) ++ ++/* 4324 Chip specific ChipControl1 register bits */ ++#define CCTRL1_4324_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ ++#define CCTRL1_4324_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ ++ ++ ++/* 4313 resources */ ++#define RES4313_BB_PU_RSRC 0 ++#define RES4313_ILP_REQ_RSRC 1 ++#define RES4313_XTAL_PU_RSRC 2 ++#define RES4313_ALP_AVAIL_RSRC 3 ++#define RES4313_RADIO_PU_RSRC 4 ++#define RES4313_BG_PU_RSRC 5 ++#define RES4313_VREG1P4_PU_RSRC 6 ++#define RES4313_AFE_PWRSW_RSRC 7 ++#define RES4313_RX_PWRSW_RSRC 8 ++#define RES4313_TX_PWRSW_RSRC 9 ++#define RES4313_BB_PWRSW_RSRC 10 ++#define RES4313_SYNTH_PWRSW_RSRC 11 ++#define RES4313_MISC_PWRSW_RSRC 12 ++#define RES4313_BB_PLL_PWRSW_RSRC 13 ++#define RES4313_HT_AVAIL_RSRC 14 ++#define RES4313_MACPHY_CLK_AVAIL_RSRC 15 ++ ++/* 4313 chip-specific ChipStatus register bits */ ++#define CST4313_SPROM_PRESENT 1 ++#define CST4313_OTP_PRESENT 2 ++#define CST4313_SPROM_OTP_SEL_MASK 0x00000002 ++#define CST4313_SPROM_OTP_SEL_SHIFT 0 ++ ++/* 4313 Chip specific ChipControl register bits */ ++#define CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */ ++ ++/* PMU respources for 4314 */ ++#define RES4314_LPLDO_PU 0 ++#define RES4314_PMU_SLEEP_DIS 1 ++#define RES4314_PMU_BG_PU 2 ++#define RES4314_CBUCK_LPOM_PU 3 ++#define RES4314_CBUCK_PFM_PU 4 ++#define RES4314_CLDO_PU 5 ++#define RES4314_LPLDO2_LVM 6 ++#define RES4314_WL_PMU_PU 7 ++#define RES4314_LNLDO_PU 8 ++#define RES4314_LDO3P3_PU 9 ++#define RES4314_OTP_PU 10 ++#define RES4314_XTAL_PU 11 ++#define RES4314_WL_PWRSW_PU 12 ++#define RES4314_LQ_AVAIL 13 ++#define RES4314_LOGIC_RET 14 ++#define RES4314_MEM_SLEEP 15 ++#define RES4314_MACPHY_RET 16 ++#define RES4314_WL_CORE_READY 17 ++#define RES4314_ILP_REQ 18 ++#define RES4314_ALP_AVAIL 19 ++#define RES4314_MISC_PWRSW_PU 20 ++#define RES4314_SYNTH_PWRSW_PU 21 ++#define RES4314_RX_PWRSW_PU 22 ++#define RES4314_RADIO_PU 23 ++#define RES4314_VCO_LDO_PU 24 ++#define RES4314_AFE_LDO_PU 25 ++#define RES4314_RX_LDO_PU 26 ++#define RES4314_TX_LDO_PU 27 ++#define RES4314_HT_AVAIL 28 ++#define RES4314_MACPHY_CLK_AVAIL 29 ++ ++/* 4314 chip-specific ChipStatus register bits */ ++#define CST4314_OTP_ENABLED 0x00200000 ++ ++/* 43228 resources */ ++#define RES43228_NOT_USED 0 ++#define RES43228_ILP_REQUEST 1 ++#define RES43228_XTAL_PU 2 ++#define RES43228_ALP_AVAIL 3 ++#define RES43228_PLL_EN 4 ++#define RES43228_HT_PHY_AVAIL 5 ++ ++/* 43228 chipstatus reg bits */ ++#define CST43228_ILP_DIV_EN 0x1 ++#define CST43228_OTP_PRESENT 0x2 ++#define CST43228_SERDES_REFCLK_PADSEL 0x4 ++#define CST43228_SDIO_MODE 0x8 ++#define CST43228_SDIO_OTP_PRESENT 0x10 ++#define CST43228_SDIO_RESET 0x20 ++ ++/* 4706 chipstatus reg bits */ ++#define CST4706_PKG_OPTION (1<<0) /* 0: full-featured package 1: low-cost package */ ++#define CST4706_SFLASH_PRESENT (1<<1) /* 0: parallel, 1: serial flash is present */ ++#define CST4706_SFLASH_TYPE (1<<2) /* 0: 8b-p/ST-s flash, 1: 16b-p/Atmal-s flash */ ++#define CST4706_MIPS_BENDIAN (1<<3) /* 0: little, 1: big endian */ ++#define CST4706_PCIE1_DISABLE (1<<5) /* PCIE1 enable strap pin */ ++ ++/* 4706 flashstrconfig reg bits */ ++#define FLSTRCF4706_MASK 0x000000ff ++#define FLSTRCF4706_SF1 0x00000001 /* 2nd serial flash present */ ++#define FLSTRCF4706_PF1 0x00000002 /* 2nd parallel flash present */ ++#define FLSTRCF4706_SF1_TYPE 0x00000004 /* 2nd serial flash type : 0 : ST, 1 : Atmel */ ++#define FLSTRCF4706_NF1 0x00000008 /* 2nd NAND flash present */ ++#define FLSTRCF4706_1ST_MADDR_SEG_MASK 0x000000f0 /* Valid value mask */ ++#define FLSTRCF4706_1ST_MADDR_SEG_4MB 0x00000010 /* 4MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_8MB 0x00000020 /* 8MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_16MB 0x00000030 /* 16MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_32MB 0x00000040 /* 32MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_64MB 0x00000050 /* 64MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_128MB 0x00000060 /* 128MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_256MB 0x00000070 /* 256MB */ ++ ++/* 4360 Chip specific ChipControl register bits */ ++#define CCTRL4360_SECI_MODE (1 << 2) ++#define CCTRL4360_BTSWCTRL_MODE (1 << 3) ++#define CCTRL4360_EXTRA_FEMCTRL_MODE (1 << 8) ++#define CCTRL4360_BT_LGCY_MODE (1 << 9) ++#define CCTRL4360_CORE2FEMCTRL4_ON (1 << 21) ++ ++/* 4360 PMU resources and chip status bits */ ++#define RES4360_REGULATOR 0 ++#define RES4360_ILP_AVAIL 1 ++#define RES4360_ILP_REQ 2 ++#define RES4360_XTAL_LDO_PU 3 ++#define RES4360_XTAL_PU 4 ++#define RES4360_ALP_AVAIL 5 ++#define RES4360_BBPLLPWRSW_PU 6 ++#define RES4360_HT_AVAIL 7 ++#define RES4360_OTP_PU 8 ++ ++#define CST4360_XTAL_40MZ 0x00000001 ++#define CST4360_SFLASH 0x00000002 ++#define CST4360_SPROM_PRESENT 0x00000004 ++#define CST4360_SFLASH_TYPE 0x00000004 ++#define CST4360_OTP_ENABLED 0x00000008 ++#define CST4360_REMAP_ROM 0x00000010 ++#define CST4360_RSRC_INIT_MODE_MASK 0x00000060 ++#define CST4360_RSRC_INIT_MODE_SHIFT 5 ++#define CST4360_ILP_DIVEN 0x00000080 ++#define CST4360_MODE_USB 0x00000100 ++#define CST4360_SPROM_SIZE_MASK 0x00000600 ++#define CST4360_SPROM_SIZE_SHIFT 9 ++#define CST4360_BBPLL_LOCK 0x00000800 ++#define CST4360_AVBBPLL_LOCK 0x00001000 ++#define CST4360_USBBBPLL_LOCK 0x00002000 ++ ++#define CCTRL_4360_UART_SEL 0x2 ++ ++/* 4335 resources */ ++#define RES4335_LPLDO_PO 0 ++#define RES4335_PMU_BG_PU 1 ++#define RES4335_PMU_SLEEP 2 ++#define RES4335_RSVD_3 3 ++#define RES4335_CBUCK_LPOM_PU 4 ++#define RES4335_CBUCK_PFM_PU 5 ++#define RES4335_RSVD_6 6 ++#define RES4335_RSVD_7 7 ++#define RES4335_LNLDO_PU 8 ++#define RES4335_XTALLDO_PU 9 ++#define RES4335_LDO3P3_PU 10 ++#define RES4335_OTP_PU 11 ++#define RES4335_XTAL_PU 12 ++#define RES4335_SR_CLK_START 13 ++#define RES4335_LQ_AVAIL 14 ++#define RES4335_LQ_START 15 ++#define RES4335_RSVD_16 16 ++#define RES4335_WL_CORE_RDY 17 ++#define RES4335_ILP_REQ 18 ++#define RES4335_ALP_AVAIL 19 ++#define RES4335_MINI_PMU 20 ++#define RES4335_RADIO_PU 21 ++#define RES4335_SR_CLK_STABLE 22 ++#define RES4335_SR_SAVE_RESTORE 23 ++#define RES4335_SR_PHY_PWRSW 24 ++#define RES4335_SR_VDDM_PWRSW 25 ++#define RES4335_SR_SUBCORE_PWRSW 26 ++#define RES4335_SR_SLEEP 27 ++#define RES4335_HT_START 28 ++#define RES4335_HT_AVAIL 29 ++#define RES4335_MACPHY_CLKAVAIL 30 ++ ++/* 4335 Chip specific ChipStatus register bits */ ++#define CST4335_SPROM_MASK 0x00000020 ++#define CST4335_SFLASH_MASK 0x00000040 ++#define CST4335_RES_INIT_MODE_SHIFT 7 ++#define CST4335_RES_INIT_MODE_MASK 0x00000180 ++#define CST4335_CHIPMODE_MASK 0xF ++#define CST4335_CHIPMODE_SDIOD(cs) (((cs) & (1 << 0)) != 0) /* SDIO */ ++#define CST4335_CHIPMODE_GSPI(cs) (((cs) & (1 << 1)) != 0) /* gSPI */ ++#define CST4335_CHIPMODE_USB20D(cs) (((cs) & (1 << 2)) != 0) /* USB || USBDA */ ++#define CST4335_CHIPMODE_PCIE(cs) (((cs) & (1 << 3)) != 0) /* PCIE */ ++ ++/* 4335 Chip specific ChipControl1 register bits */ ++#define CCTRL1_4335_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ ++#define CCTRL1_4335_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ ++ ++ ++#define CR4_RAM_BASE (0x180000) ++ ++/* 4335 resources--END */ ++ ++/* GCI chipcontrol register indices */ ++#define CC_GCI_CHIPCTRL_00 (0) ++#define CC_GCI_CHIPCTRL_01 (1) ++#define CC_GCI_CHIPCTRL_02 (2) ++#define CC_GCI_CHIPCTRL_03 (3) ++#define CC_GCI_CHIPCTRL_04 (4) ++#define CC_GCI_CHIPCTRL_05 (5) ++#define CC_GCI_CHIPCTRL_06 (6) ++#define CC_GCI_CHIPCTRL_07 (7) ++#define CC_GCI_CHIPCTRL_08 (8) ++ ++#define CC_GCI_NUMCHIPCTRLREGS(cap1) ((cap1 & 0xF00) >> 8) ++ ++/* 4335 pins ++* note: only the values set as default/used are added here. ++*/ ++#define CC4335_PIN_GPIO_00 (0) ++#define CC4335_PIN_GPIO_01 (1) ++#define CC4335_PIN_GPIO_02 (2) ++#define CC4335_PIN_GPIO_03 (3) ++#define CC4335_PIN_GPIO_04 (4) ++#define CC4335_PIN_GPIO_05 (5) ++#define CC4335_PIN_GPIO_06 (6) ++#define CC4335_PIN_GPIO_07 (7) ++#define CC4335_PIN_GPIO_08 (8) ++#define CC4335_PIN_GPIO_09 (9) ++#define CC4335_PIN_GPIO_10 (10) ++#define CC4335_PIN_GPIO_11 (11) ++#define CC4335_PIN_GPIO_12 (12) ++#define CC4335_PIN_GPIO_13 (13) ++#define CC4335_PIN_GPIO_14 (14) ++#define CC4335_PIN_GPIO_15 (15) ++#define CC4335_PIN_SDIO_CLK (16) ++#define CC4335_PIN_SDIO_CMD (17) ++#define CC4335_PIN_SDIO_DATA0 (18) ++#define CC4335_PIN_SDIO_DATA1 (19) ++#define CC4335_PIN_SDIO_DATA2 (20) ++#define CC4335_PIN_SDIO_DATA3 (21) ++#define CC4335_PIN_RF_SW_CTRL_0 (22) ++#define CC4335_PIN_RF_SW_CTRL_1 (23) ++#define CC4335_PIN_RF_SW_CTRL_2 (24) ++#define CC4335_PIN_RF_SW_CTRL_3 (25) ++#define CC4335_PIN_RF_SW_CTRL_4 (26) ++#define CC4335_PIN_RF_SW_CTRL_5 (27) ++#define CC4335_PIN_RF_SW_CTRL_6 (28) ++#define CC4335_PIN_RF_SW_CTRL_7 (29) ++#define CC4335_PIN_RF_SW_CTRL_8 (30) ++#define CC4335_PIN_RF_SW_CTRL_9 (31) ++ ++/* 4335 GCI function sel values ++*/ ++#define CC4335_FNSEL_HWDEF (0) ++#define CC4335_FNSEL_SAMEASPIN (1) ++#define CC4335_FNSEL_GPIO0 (2) ++#define CC4335_FNSEL_GPIO1 (3) ++#define CC4335_FNSEL_GCI0 (4) ++#define CC4335_FNSEL_GCI1 (5) ++#define CC4335_FNSEL_UART (6) ++#define CC4335_FNSEL_SFLASH (7) ++#define CC4335_FNSEL_SPROM (8) ++#define CC4335_FNSEL_MISC0 (9) ++#define CC4335_FNSEL_MISC1 (10) ++#define CC4335_FNSEL_MISC2 (11) ++#define CC4335_FNSEL_IND (12) ++#define CC4335_FNSEL_PDN (13) ++#define CC4335_FNSEL_PUP (14) ++#define CC4335_FNSEL_TRI (15) ++ ++/* find the 4 bit mask given the bit position */ ++#define GCIMASK(pos) (((uint32)0xF) << pos) ++ ++/* get the value which can be used to directly OR with chipcontrol reg */ ++#define GCIPOSVAL(val, pos) ((((uint32)val) << pos) & GCIMASK(pos)) ++ ++/* 4335 MUX options. each nibble belongs to a setting. Non-zero value specifies a logic ++* for now only UART for bootloader. ++*/ ++#define MUXENAB4335_UART_MASK (0x0000000f) ++ ++ ++/* defines to detect active host interface in use */ ++#define CHIP_HOSTIF_USB(sih) (si_chip_hostif(sih) & CST4360_MODE_USB) ++ ++/* ++* Maximum delay for the PMU state transition in us. ++* This is an upper bound intended for spinwaits etc. ++*/ ++#define PMU_MAX_TRANSITION_DLY 15000 ++ ++/* PMU resource up transition time in ILP cycles */ ++#define PMURES_UP_TRANSITION 2 ++ ++ ++/* SECI configuration */ ++#define SECI_MODE_UART 0x0 ++#define SECI_MODE_SECI 0x1 ++#define SECI_MODE_LEGACY_3WIRE_BT 0x2 ++#define SECI_MODE_LEGACY_3WIRE_WLAN 0x3 ++#define SECI_MODE_HALF_SECI 0x4 ++ ++#define SECI_RESET (1 << 0) ++#define SECI_RESET_BAR_UART (1 << 1) ++#define SECI_ENAB_SECI_ECI (1 << 2) ++#define SECI_ENAB_SECIOUT_DIS (1 << 3) ++#define SECI_MODE_MASK 0x7 ++#define SECI_MODE_SHIFT 4 /* (bits 5, 6, 7) */ ++#define SECI_UPD_SECI (1 << 7) ++ ++#define SECI_SIGNOFF_0 0xDB ++#define SECI_SIGNOFF_1 0 ++ ++/* seci clk_ctl_st bits */ ++#define CLKCTL_STS_SECI_CLK_REQ (1 << 8) ++#define CLKCTL_STS_SECI_CLK_AVAIL (1 << 24) ++ ++#define SECI_UART_MSR_CTS_STATE (1 << 0) ++#define SECI_UART_MSR_RTS_STATE (1 << 1) ++#define SECI_UART_SECI_IN_STATE (1 << 2) ++#define SECI_UART_SECI_IN2_STATE (1 << 3) ++ ++/* SECI UART LCR/MCR register bits */ ++#define SECI_UART_LCR_STOP_BITS (1 << 0) /* 0 - 1bit, 1 - 2bits */ ++#define SECI_UART_LCR_PARITY_EN (1 << 1) ++#define SECI_UART_LCR_PARITY (1 << 2) /* 0 - odd, 1 - even */ ++#define SECI_UART_LCR_RX_EN (1 << 3) ++#define SECI_UART_LCR_LBRK_CTRL (1 << 4) /* 1 => SECI_OUT held low */ ++#define SECI_UART_LCR_TXO_EN (1 << 5) ++#define SECI_UART_LCR_RTSO_EN (1 << 6) ++#define SECI_UART_LCR_SLIPMODE_EN (1 << 7) ++#define SECI_UART_LCR_RXCRC_CHK (1 << 8) ++#define SECI_UART_LCR_TXCRC_INV (1 << 9) ++#define SECI_UART_LCR_TXCRC_LSBF (1 << 10) ++#define SECI_UART_LCR_TXCRC_EN (1 << 11) ++ ++#define SECI_UART_MCR_TX_EN (1 << 0) ++#define SECI_UART_MCR_PRTS (1 << 1) ++#define SECI_UART_MCR_SWFLCTRL_EN (1 << 2) ++#define SECI_UART_MCR_HIGHRATE_EN (1 << 3) ++#define SECI_UART_MCR_LOOPBK_EN (1 << 4) ++#define SECI_UART_MCR_AUTO_RTS (1 << 5) ++#define SECI_UART_MCR_AUTO_TX_DIS (1 << 6) ++#define SECI_UART_MCR_BAUD_ADJ_EN (1 << 7) ++#define SECI_UART_MCR_XONOFF_RPT (1 << 9) ++ ++/* WLAN channel numbers - used from wifi.h */ ++ ++/* WLAN BW */ ++#define ECI_BW_20 0x0 ++#define ECI_BW_25 0x1 ++#define ECI_BW_30 0x2 ++#define ECI_BW_35 0x3 ++#define ECI_BW_40 0x4 ++#define ECI_BW_45 0x5 ++#define ECI_BW_50 0x6 ++#define ECI_BW_ALL 0x7 ++ ++/* WLAN - number of antenna */ ++#define WLAN_NUM_ANT1 TXANT_0 ++#define WLAN_NUM_ANT2 TXANT_1 ++ ++#endif /* _SBCHIPC_H */ +diff --git a/drivers/net/wireless/ap6211/include/sbconfig.h b/drivers/net/wireless/ap6211/include/sbconfig.h +new file mode 100755 +index 0000000..73ddadd +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sbconfig.h +@@ -0,0 +1,282 @@ ++/* ++ * Broadcom SiliconBackplane hardware register definitions. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sbconfig.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _SBCONFIG_H ++#define _SBCONFIG_H ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif ++ ++/* enumeration in SB is based on the premise that cores are contiguos in the ++ * enumeration space. ++ */ ++#define SB_BUS_SIZE 0x10000 /* Each bus gets 64Kbytes for cores */ ++#define SB_BUS_BASE(b) (SI_ENUM_BASE + (b) * SB_BUS_SIZE) ++#define SB_BUS_MAXCORES (SB_BUS_SIZE / SI_CORE_SIZE) /* Max cores per bus */ ++ ++/* ++ * Sonics Configuration Space Registers. ++ */ ++#define SBCONFIGOFF 0xf00 /* core sbconfig regs are top 256bytes of regs */ ++#define SBCONFIGSIZE 256 /* sizeof (sbconfig_t) */ ++ ++#define SBIPSFLAG 0x08 ++#define SBTPSFLAG 0x18 ++#define SBTMERRLOGA 0x48 /* sonics >= 2.3 */ ++#define SBTMERRLOG 0x50 /* sonics >= 2.3 */ ++#define SBADMATCH3 0x60 ++#define SBADMATCH2 0x68 ++#define SBADMATCH1 0x70 ++#define SBIMSTATE 0x90 ++#define SBINTVEC 0x94 ++#define SBTMSTATELOW 0x98 ++#define SBTMSTATEHIGH 0x9c ++#define SBBWA0 0xa0 ++#define SBIMCONFIGLOW 0xa8 ++#define SBIMCONFIGHIGH 0xac ++#define SBADMATCH0 0xb0 ++#define SBTMCONFIGLOW 0xb8 ++#define SBTMCONFIGHIGH 0xbc ++#define SBBCONFIG 0xc0 ++#define SBBSTATE 0xc8 ++#define SBACTCNFG 0xd8 ++#define SBFLAGST 0xe8 ++#define SBIDLOW 0xf8 ++#define SBIDHIGH 0xfc ++ ++/* All the previous registers are above SBCONFIGOFF, but with Sonics 2.3, we have ++ * a few registers *below* that line. I think it would be very confusing to try ++ * and change the value of SBCONFIGOFF, so I'm definig them as absolute offsets here, ++ */ ++ ++#define SBIMERRLOGA 0xea8 ++#define SBIMERRLOG 0xeb0 ++#define SBTMPORTCONNID0 0xed8 ++#define SBTMPORTLOCK0 0xef8 ++ ++#ifndef _LANGUAGE_ASSEMBLY ++ ++typedef volatile struct _sbconfig { ++ uint32 PAD[2]; ++ uint32 sbipsflag; /* initiator port ocp slave flag */ ++ uint32 PAD[3]; ++ uint32 sbtpsflag; /* target port ocp slave flag */ ++ uint32 PAD[11]; ++ uint32 sbtmerrloga; /* (sonics >= 2.3) */ ++ uint32 PAD; ++ uint32 sbtmerrlog; /* (sonics >= 2.3) */ ++ uint32 PAD[3]; ++ uint32 sbadmatch3; /* address match3 */ ++ uint32 PAD; ++ uint32 sbadmatch2; /* address match2 */ ++ uint32 PAD; ++ uint32 sbadmatch1; /* address match1 */ ++ uint32 PAD[7]; ++ uint32 sbimstate; /* initiator agent state */ ++ uint32 sbintvec; /* interrupt mask */ ++ uint32 sbtmstatelow; /* target state */ ++ uint32 sbtmstatehigh; /* target state */ ++ uint32 sbbwa0; /* bandwidth allocation table0 */ ++ uint32 PAD; ++ uint32 sbimconfiglow; /* initiator configuration */ ++ uint32 sbimconfighigh; /* initiator configuration */ ++ uint32 sbadmatch0; /* address match0 */ ++ uint32 PAD; ++ uint32 sbtmconfiglow; /* target configuration */ ++ uint32 sbtmconfighigh; /* target configuration */ ++ uint32 sbbconfig; /* broadcast configuration */ ++ uint32 PAD; ++ uint32 sbbstate; /* broadcast state */ ++ uint32 PAD[3]; ++ uint32 sbactcnfg; /* activate configuration */ ++ uint32 PAD[3]; ++ uint32 sbflagst; /* current sbflags */ ++ uint32 PAD[3]; ++ uint32 sbidlow; /* identification */ ++ uint32 sbidhigh; /* identification */ ++} sbconfig_t; ++ ++#endif /* _LANGUAGE_ASSEMBLY */ ++ ++/* sbipsflag */ ++#define SBIPS_INT1_MASK 0x3f /* which sbflags get routed to mips interrupt 1 */ ++#define SBIPS_INT1_SHIFT 0 ++#define SBIPS_INT2_MASK 0x3f00 /* which sbflags get routed to mips interrupt 2 */ ++#define SBIPS_INT2_SHIFT 8 ++#define SBIPS_INT3_MASK 0x3f0000 /* which sbflags get routed to mips interrupt 3 */ ++#define SBIPS_INT3_SHIFT 16 ++#define SBIPS_INT4_MASK 0x3f000000 /* which sbflags get routed to mips interrupt 4 */ ++#define SBIPS_INT4_SHIFT 24 ++ ++/* sbtpsflag */ ++#define SBTPS_NUM0_MASK 0x3f /* interrupt sbFlag # generated by this core */ ++#define SBTPS_F0EN0 0x40 /* interrupt is always sent on the backplane */ ++ ++/* sbtmerrlog */ ++#define SBTMEL_CM 0x00000007 /* command */ ++#define SBTMEL_CI 0x0000ff00 /* connection id */ ++#define SBTMEL_EC 0x0f000000 /* error code */ ++#define SBTMEL_ME 0x80000000 /* multiple error */ ++ ++/* sbimstate */ ++#define SBIM_PC 0xf /* pipecount */ ++#define SBIM_AP_MASK 0x30 /* arbitration policy */ ++#define SBIM_AP_BOTH 0x00 /* use both timeslaces and token */ ++#define SBIM_AP_TS 0x10 /* use timesliaces only */ ++#define SBIM_AP_TK 0x20 /* use token only */ ++#define SBIM_AP_RSV 0x30 /* reserved */ ++#define SBIM_IBE 0x20000 /* inbanderror */ ++#define SBIM_TO 0x40000 /* timeout */ ++#define SBIM_BY 0x01800000 /* busy (sonics >= 2.3) */ ++#define SBIM_RJ 0x02000000 /* reject (sonics >= 2.3) */ ++ ++/* sbtmstatelow */ ++#define SBTML_RESET 0x0001 /* reset */ ++#define SBTML_REJ_MASK 0x0006 /* reject field */ ++#define SBTML_REJ 0x0002 /* reject */ ++#define SBTML_TMPREJ 0x0004 /* temporary reject, for error recovery */ ++ ++#define SBTML_SICF_SHIFT 16 /* Shift to locate the SI control flags in sbtml */ ++ ++/* sbtmstatehigh */ ++#define SBTMH_SERR 0x0001 /* serror */ ++#define SBTMH_INT 0x0002 /* interrupt */ ++#define SBTMH_BUSY 0x0004 /* busy */ ++#define SBTMH_TO 0x0020 /* timeout (sonics >= 2.3) */ ++ ++#define SBTMH_SISF_SHIFT 16 /* Shift to locate the SI status flags in sbtmh */ ++ ++/* sbbwa0 */ ++#define SBBWA_TAB0_MASK 0xffff /* lookup table 0 */ ++#define SBBWA_TAB1_MASK 0xffff /* lookup table 1 */ ++#define SBBWA_TAB1_SHIFT 16 ++ ++/* sbimconfiglow */ ++#define SBIMCL_STO_MASK 0x7 /* service timeout */ ++#define SBIMCL_RTO_MASK 0x70 /* request timeout */ ++#define SBIMCL_RTO_SHIFT 4 ++#define SBIMCL_CID_MASK 0xff0000 /* connection id */ ++#define SBIMCL_CID_SHIFT 16 ++ ++/* sbimconfighigh */ ++#define SBIMCH_IEM_MASK 0xc /* inband error mode */ ++#define SBIMCH_TEM_MASK 0x30 /* timeout error mode */ ++#define SBIMCH_TEM_SHIFT 4 ++#define SBIMCH_BEM_MASK 0xc0 /* bus error mode */ ++#define SBIMCH_BEM_SHIFT 6 ++ ++/* sbadmatch0 */ ++#define SBAM_TYPE_MASK 0x3 /* address type */ ++#define SBAM_AD64 0x4 /* reserved */ ++#define SBAM_ADINT0_MASK 0xf8 /* type0 size */ ++#define SBAM_ADINT0_SHIFT 3 ++#define SBAM_ADINT1_MASK 0x1f8 /* type1 size */ ++#define SBAM_ADINT1_SHIFT 3 ++#define SBAM_ADINT2_MASK 0x1f8 /* type2 size */ ++#define SBAM_ADINT2_SHIFT 3 ++#define SBAM_ADEN 0x400 /* enable */ ++#define SBAM_ADNEG 0x800 /* negative decode */ ++#define SBAM_BASE0_MASK 0xffffff00 /* type0 base address */ ++#define SBAM_BASE0_SHIFT 8 ++#define SBAM_BASE1_MASK 0xfffff000 /* type1 base address for the core */ ++#define SBAM_BASE1_SHIFT 12 ++#define SBAM_BASE2_MASK 0xffff0000 /* type2 base address for the core */ ++#define SBAM_BASE2_SHIFT 16 ++ ++/* sbtmconfiglow */ ++#define SBTMCL_CD_MASK 0xff /* clock divide */ ++#define SBTMCL_CO_MASK 0xf800 /* clock offset */ ++#define SBTMCL_CO_SHIFT 11 ++#define SBTMCL_IF_MASK 0xfc0000 /* interrupt flags */ ++#define SBTMCL_IF_SHIFT 18 ++#define SBTMCL_IM_MASK 0x3000000 /* interrupt mode */ ++#define SBTMCL_IM_SHIFT 24 ++ ++/* sbtmconfighigh */ ++#define SBTMCH_BM_MASK 0x3 /* busy mode */ ++#define SBTMCH_RM_MASK 0x3 /* retry mode */ ++#define SBTMCH_RM_SHIFT 2 ++#define SBTMCH_SM_MASK 0x30 /* stop mode */ ++#define SBTMCH_SM_SHIFT 4 ++#define SBTMCH_EM_MASK 0x300 /* sb error mode */ ++#define SBTMCH_EM_SHIFT 8 ++#define SBTMCH_IM_MASK 0xc00 /* int mode */ ++#define SBTMCH_IM_SHIFT 10 ++ ++/* sbbconfig */ ++#define SBBC_LAT_MASK 0x3 /* sb latency */ ++#define SBBC_MAX0_MASK 0xf0000 /* maxccntr0 */ ++#define SBBC_MAX0_SHIFT 16 ++#define SBBC_MAX1_MASK 0xf00000 /* maxccntr1 */ ++#define SBBC_MAX1_SHIFT 20 ++ ++/* sbbstate */ ++#define SBBS_SRD 0x1 /* st reg disable */ ++#define SBBS_HRD 0x2 /* hold reg disable */ ++ ++/* sbidlow */ ++#define SBIDL_CS_MASK 0x3 /* config space */ ++#define SBIDL_AR_MASK 0x38 /* # address ranges supported */ ++#define SBIDL_AR_SHIFT 3 ++#define SBIDL_SYNCH 0x40 /* sync */ ++#define SBIDL_INIT 0x80 /* initiator */ ++#define SBIDL_MINLAT_MASK 0xf00 /* minimum backplane latency */ ++#define SBIDL_MINLAT_SHIFT 8 ++#define SBIDL_MAXLAT 0xf000 /* maximum backplane latency */ ++#define SBIDL_MAXLAT_SHIFT 12 ++#define SBIDL_FIRST 0x10000 /* this initiator is first */ ++#define SBIDL_CW_MASK 0xc0000 /* cycle counter width */ ++#define SBIDL_CW_SHIFT 18 ++#define SBIDL_TP_MASK 0xf00000 /* target ports */ ++#define SBIDL_TP_SHIFT 20 ++#define SBIDL_IP_MASK 0xf000000 /* initiator ports */ ++#define SBIDL_IP_SHIFT 24 ++#define SBIDL_RV_MASK 0xf0000000 /* sonics backplane revision code */ ++#define SBIDL_RV_SHIFT 28 ++#define SBIDL_RV_2_2 0x00000000 /* version 2.2 or earlier */ ++#define SBIDL_RV_2_3 0x10000000 /* version 2.3 */ ++ ++/* sbidhigh */ ++#define SBIDH_RC_MASK 0x000f /* revision code */ ++#define SBIDH_RCE_MASK 0x7000 /* revision code extension field */ ++#define SBIDH_RCE_SHIFT 8 ++#define SBCOREREV(sbidh) \ ++ ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | ((sbidh) & SBIDH_RC_MASK)) ++#define SBIDH_CC_MASK 0x8ff0 /* core code */ ++#define SBIDH_CC_SHIFT 4 ++#define SBIDH_VC_MASK 0xffff0000 /* vendor code */ ++#define SBIDH_VC_SHIFT 16 ++ ++#define SB_COMMIT 0xfd8 /* update buffered registers value */ ++ ++/* vendor codes */ ++#define SB_VEND_BCM 0x4243 /* Broadcom's SB vendor code */ ++ ++#endif /* _SBCONFIG_H */ +diff --git a/drivers/net/wireless/ap6211/include/sbhnddma.h b/drivers/net/wireless/ap6211/include/sbhnddma.h +new file mode 100755 +index 0000000..40ebd8a +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sbhnddma.h +@@ -0,0 +1,384 @@ ++/* ++ * Generic Broadcom Home Networking Division (HND) DMA engine HW interface ++ * This supports the following chips: BCM42xx, 44xx, 47xx . ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sbhnddma.h 309193 2012-01-19 00:03:57Z $ ++ */ ++ ++#ifndef _sbhnddma_h_ ++#define _sbhnddma_h_ ++ ++/* DMA structure: ++ * support two DMA engines: 32 bits address or 64 bit addressing ++ * basic DMA register set is per channel(transmit or receive) ++ * a pair of channels is defined for convenience ++ */ ++ ++ ++/* 32 bits addressing */ ++ ++/* dma registers per channel(xmt or rcv) */ ++typedef volatile struct { ++ uint32 control; /* enable, et al */ ++ uint32 addr; /* descriptor ring base address (4K aligned) */ ++ uint32 ptr; /* last descriptor posted to chip */ ++ uint32 status; /* current active descriptor, et al */ ++} dma32regs_t; ++ ++typedef volatile struct { ++ dma32regs_t xmt; /* dma tx channel */ ++ dma32regs_t rcv; /* dma rx channel */ ++} dma32regp_t; ++ ++typedef volatile struct { /* diag access */ ++ uint32 fifoaddr; /* diag address */ ++ uint32 fifodatalow; /* low 32bits of data */ ++ uint32 fifodatahigh; /* high 32bits of data */ ++ uint32 pad; /* reserved */ ++} dma32diag_t; ++ ++/* ++ * DMA Descriptor ++ * Descriptors are only read by the hardware, never written back. ++ */ ++typedef volatile struct { ++ uint32 ctrl; /* misc control bits & bufcount */ ++ uint32 addr; /* data buffer address */ ++} dma32dd_t; ++ ++/* ++ * Each descriptor ring must be 4096byte aligned, and fit within a single 4096byte page. ++ */ ++#define D32RINGALIGN_BITS 12 ++#define D32MAXRINGSZ (1 << D32RINGALIGN_BITS) ++#define D32RINGALIGN (1 << D32RINGALIGN_BITS) ++ ++#define D32MAXDD (D32MAXRINGSZ / sizeof (dma32dd_t)) ++ ++/* transmit channel control */ ++#define XC_XE ((uint32)1 << 0) /* transmit enable */ ++#define XC_SE ((uint32)1 << 1) /* transmit suspend request */ ++#define XC_LE ((uint32)1 << 2) /* loopback enable */ ++#define XC_FL ((uint32)1 << 4) /* flush request */ ++#define XC_MR_MASK 0x000000C0 /* Multiple outstanding reads */ ++#define XC_MR_SHIFT 6 ++#define XC_PD ((uint32)1 << 11) /* parity check disable */ ++#define XC_AE ((uint32)3 << 16) /* address extension bits */ ++#define XC_AE_SHIFT 16 ++#define XC_BL_MASK 0x001C0000 /* BurstLen bits */ ++#define XC_BL_SHIFT 18 ++#define XC_PC_MASK 0x00E00000 /* Prefetch control */ ++#define XC_PC_SHIFT 21 ++#define XC_PT_MASK 0x03000000 /* Prefetch threshold */ ++#define XC_PT_SHIFT 24 ++ ++/* Multiple outstanding reads */ ++#define DMA_MR_1 0 ++#define DMA_MR_2 1 ++/* 2, 3: reserved */ ++ ++/* DMA Burst Length in bytes */ ++#define DMA_BL_16 0 ++#define DMA_BL_32 1 ++#define DMA_BL_64 2 ++#define DMA_BL_128 3 ++#define DMA_BL_256 4 ++#define DMA_BL_512 5 ++#define DMA_BL_1024 6 ++ ++/* Prefetch control */ ++#define DMA_PC_0 0 ++#define DMA_PC_4 1 ++#define DMA_PC_8 2 ++#define DMA_PC_16 3 ++/* others: reserved */ ++ ++/* Prefetch threshold */ ++#define DMA_PT_1 0 ++#define DMA_PT_2 1 ++#define DMA_PT_4 2 ++#define DMA_PT_8 3 ++ ++/* transmit descriptor table pointer */ ++#define XP_LD_MASK 0xfff /* last valid descriptor */ ++ ++/* transmit channel status */ ++#define XS_CD_MASK 0x0fff /* current descriptor pointer */ ++#define XS_XS_MASK 0xf000 /* transmit state */ ++#define XS_XS_SHIFT 12 ++#define XS_XS_DISABLED 0x0000 /* disabled */ ++#define XS_XS_ACTIVE 0x1000 /* active */ ++#define XS_XS_IDLE 0x2000 /* idle wait */ ++#define XS_XS_STOPPED 0x3000 /* stopped */ ++#define XS_XS_SUSP 0x4000 /* suspend pending */ ++#define XS_XE_MASK 0xf0000 /* transmit errors */ ++#define XS_XE_SHIFT 16 ++#define XS_XE_NOERR 0x00000 /* no error */ ++#define XS_XE_DPE 0x10000 /* descriptor protocol error */ ++#define XS_XE_DFU 0x20000 /* data fifo underrun */ ++#define XS_XE_BEBR 0x30000 /* bus error on buffer read */ ++#define XS_XE_BEDA 0x40000 /* bus error on descriptor access */ ++#define XS_AD_MASK 0xfff00000 /* active descriptor */ ++#define XS_AD_SHIFT 20 ++ ++/* receive channel control */ ++#define RC_RE ((uint32)1 << 0) /* receive enable */ ++#define RC_RO_MASK 0xfe /* receive frame offset */ ++#define RC_RO_SHIFT 1 ++#define RC_FM ((uint32)1 << 8) /* direct fifo receive (pio) mode */ ++#define RC_SH ((uint32)1 << 9) /* separate rx header descriptor enable */ ++#define RC_OC ((uint32)1 << 10) /* overflow continue */ ++#define RC_PD ((uint32)1 << 11) /* parity check disable */ ++#define RC_AE ((uint32)3 << 16) /* address extension bits */ ++#define RC_AE_SHIFT 16 ++#define RC_BL_MASK 0x001C0000 /* BurstLen bits */ ++#define RC_BL_SHIFT 18 ++#define RC_PC_MASK 0x00E00000 /* Prefetch control */ ++#define RC_PC_SHIFT 21 ++#define RC_PT_MASK 0x03000000 /* Prefetch threshold */ ++#define RC_PT_SHIFT 24 ++ ++/* receive descriptor table pointer */ ++#define RP_LD_MASK 0xfff /* last valid descriptor */ ++ ++/* receive channel status */ ++#define RS_CD_MASK 0x0fff /* current descriptor pointer */ ++#define RS_RS_MASK 0xf000 /* receive state */ ++#define RS_RS_SHIFT 12 ++#define RS_RS_DISABLED 0x0000 /* disabled */ ++#define RS_RS_ACTIVE 0x1000 /* active */ ++#define RS_RS_IDLE 0x2000 /* idle wait */ ++#define RS_RS_STOPPED 0x3000 /* reserved */ ++#define RS_RE_MASK 0xf0000 /* receive errors */ ++#define RS_RE_SHIFT 16 ++#define RS_RE_NOERR 0x00000 /* no error */ ++#define RS_RE_DPE 0x10000 /* descriptor protocol error */ ++#define RS_RE_DFO 0x20000 /* data fifo overflow */ ++#define RS_RE_BEBW 0x30000 /* bus error on buffer write */ ++#define RS_RE_BEDA 0x40000 /* bus error on descriptor access */ ++#define RS_AD_MASK 0xfff00000 /* active descriptor */ ++#define RS_AD_SHIFT 20 ++ ++/* fifoaddr */ ++#define FA_OFF_MASK 0xffff /* offset */ ++#define FA_SEL_MASK 0xf0000 /* select */ ++#define FA_SEL_SHIFT 16 ++#define FA_SEL_XDD 0x00000 /* transmit dma data */ ++#define FA_SEL_XDP 0x10000 /* transmit dma pointers */ ++#define FA_SEL_RDD 0x40000 /* receive dma data */ ++#define FA_SEL_RDP 0x50000 /* receive dma pointers */ ++#define FA_SEL_XFD 0x80000 /* transmit fifo data */ ++#define FA_SEL_XFP 0x90000 /* transmit fifo pointers */ ++#define FA_SEL_RFD 0xc0000 /* receive fifo data */ ++#define FA_SEL_RFP 0xd0000 /* receive fifo pointers */ ++#define FA_SEL_RSD 0xe0000 /* receive frame status data */ ++#define FA_SEL_RSP 0xf0000 /* receive frame status pointers */ ++ ++/* descriptor control flags */ ++#define CTRL_BC_MASK 0x00001fff /* buffer byte count, real data len must <= 4KB */ ++#define CTRL_AE ((uint32)3 << 16) /* address extension bits */ ++#define CTRL_AE_SHIFT 16 ++#define CTRL_PARITY ((uint32)3 << 18) /* parity bit */ ++#define CTRL_EOT ((uint32)1 << 28) /* end of descriptor table */ ++#define CTRL_IOC ((uint32)1 << 29) /* interrupt on completion */ ++#define CTRL_EOF ((uint32)1 << 30) /* end of frame */ ++#define CTRL_SOF ((uint32)1 << 31) /* start of frame */ ++ ++/* control flags in the range [27:20] are core-specific and not defined here */ ++#define CTRL_CORE_MASK 0x0ff00000 ++ ++/* 64 bits addressing */ ++ ++/* dma registers per channel(xmt or rcv) */ ++typedef volatile struct { ++ uint32 control; /* enable, et al */ ++ uint32 ptr; /* last descriptor posted to chip */ ++ uint32 addrlow; /* descriptor ring base address low 32-bits (8K aligned) */ ++ uint32 addrhigh; /* descriptor ring base address bits 63:32 (8K aligned) */ ++ uint32 status0; /* current descriptor, xmt state */ ++ uint32 status1; /* active descriptor, xmt error */ ++} dma64regs_t; ++ ++typedef volatile struct { ++ dma64regs_t tx; /* dma64 tx channel */ ++ dma64regs_t rx; /* dma64 rx channel */ ++} dma64regp_t; ++ ++typedef volatile struct { /* diag access */ ++ uint32 fifoaddr; /* diag address */ ++ uint32 fifodatalow; /* low 32bits of data */ ++ uint32 fifodatahigh; /* high 32bits of data */ ++ uint32 pad; /* reserved */ ++} dma64diag_t; ++ ++/* ++ * DMA Descriptor ++ * Descriptors are only read by the hardware, never written back. ++ */ ++typedef volatile struct { ++ uint32 ctrl1; /* misc control bits */ ++ uint32 ctrl2; /* buffer count and address extension */ ++ uint32 addrlow; /* memory address of the date buffer, bits 31:0 */ ++ uint32 addrhigh; /* memory address of the date buffer, bits 63:32 */ ++} dma64dd_t; ++ ++/* ++ * Each descriptor ring must be 8kB aligned, and fit within a contiguous 8kB physical addresss. ++ */ ++#define D64RINGALIGN_BITS 13 ++#define D64MAXRINGSZ (1 << D64RINGALIGN_BITS) ++#define D64RINGALIGN (1 << D64RINGALIGN_BITS) ++ ++#define D64MAXDD (D64MAXRINGSZ / sizeof (dma64dd_t)) ++ ++/* transmit channel control */ ++#define D64_XC_XE 0x00000001 /* transmit enable */ ++#define D64_XC_SE 0x00000002 /* transmit suspend request */ ++#define D64_XC_LE 0x00000004 /* loopback enable */ ++#define D64_XC_FL 0x00000010 /* flush request */ ++#define D64_XC_MR_MASK 0x000000C0 /* Multiple outstanding reads */ ++#define D64_XC_MR_SHIFT 6 ++#define D64_XC_PD 0x00000800 /* parity check disable */ ++#define D64_XC_AE 0x00030000 /* address extension bits */ ++#define D64_XC_AE_SHIFT 16 ++#define D64_XC_BL_MASK 0x001C0000 /* BurstLen bits */ ++#define D64_XC_BL_SHIFT 18 ++#define D64_XC_PC_MASK 0x00E00000 /* Prefetch control */ ++#define D64_XC_PC_SHIFT 21 ++#define D64_XC_PT_MASK 0x03000000 /* Prefetch threshold */ ++#define D64_XC_PT_SHIFT 24 ++ ++/* transmit descriptor table pointer */ ++#define D64_XP_LD_MASK 0x00001fff /* last valid descriptor */ ++ ++/* transmit channel status */ ++#define D64_XS0_CD_MASK 0x00001fff /* current descriptor pointer */ ++#define D64_XS0_XS_MASK 0xf0000000 /* transmit state */ ++#define D64_XS0_XS_SHIFT 28 ++#define D64_XS0_XS_DISABLED 0x00000000 /* disabled */ ++#define D64_XS0_XS_ACTIVE 0x10000000 /* active */ ++#define D64_XS0_XS_IDLE 0x20000000 /* idle wait */ ++#define D64_XS0_XS_STOPPED 0x30000000 /* stopped */ ++#define D64_XS0_XS_SUSP 0x40000000 /* suspend pending */ ++ ++#define D64_XS1_AD_MASK 0x00001fff /* active descriptor */ ++#define D64_XS1_XE_MASK 0xf0000000 /* transmit errors */ ++#define D64_XS1_XE_SHIFT 28 ++#define D64_XS1_XE_NOERR 0x00000000 /* no error */ ++#define D64_XS1_XE_DPE 0x10000000 /* descriptor protocol error */ ++#define D64_XS1_XE_DFU 0x20000000 /* data fifo underrun */ ++#define D64_XS1_XE_DTE 0x30000000 /* data transfer error */ ++#define D64_XS1_XE_DESRE 0x40000000 /* descriptor read error */ ++#define D64_XS1_XE_COREE 0x50000000 /* core error */ ++ ++/* receive channel control */ ++#define D64_RC_RE 0x00000001 /* receive enable */ ++#define D64_RC_RO_MASK 0x000000fe /* receive frame offset */ ++#define D64_RC_RO_SHIFT 1 ++#define D64_RC_FM 0x00000100 /* direct fifo receive (pio) mode */ ++#define D64_RC_SH 0x00000200 /* separate rx header descriptor enable */ ++#define D64_RC_OC 0x00000400 /* overflow continue */ ++#define D64_RC_PD 0x00000800 /* parity check disable */ ++#define D64_RC_AE 0x00030000 /* address extension bits */ ++#define D64_RC_AE_SHIFT 16 ++#define D64_RC_BL_MASK 0x001C0000 /* BurstLen bits */ ++#define D64_RC_BL_SHIFT 18 ++#define D64_RC_PC_MASK 0x00E00000 /* Prefetch control */ ++#define D64_RC_PC_SHIFT 21 ++#define D64_RC_PT_MASK 0x03000000 /* Prefetch threshold */ ++#define D64_RC_PT_SHIFT 24 ++ ++/* flags for dma controller */ ++#define DMA_CTRL_PEN (1 << 0) /* partity enable */ ++#define DMA_CTRL_ROC (1 << 1) /* rx overflow continue */ ++#define DMA_CTRL_RXMULTI (1 << 2) /* allow rx scatter to multiple descriptors */ ++#define DMA_CTRL_UNFRAMED (1 << 3) /* Unframed Rx/Tx data */ ++#define DMA_CTRL_USB_BOUNDRY4KB_WAR (1 << 4) ++#define DMA_CTRL_DMA_AVOIDANCE_WAR (1 << 5) /* DMA avoidance WAR for 4331 */ ++ ++/* receive descriptor table pointer */ ++#define D64_RP_LD_MASK 0x00001fff /* last valid descriptor */ ++ ++/* receive channel status */ ++#define D64_RS0_CD_MASK 0x00001fff /* current descriptor pointer */ ++#define D64_RS0_RS_MASK 0xf0000000 /* receive state */ ++#define D64_RS0_RS_SHIFT 28 ++#define D64_RS0_RS_DISABLED 0x00000000 /* disabled */ ++#define D64_RS0_RS_ACTIVE 0x10000000 /* active */ ++#define D64_RS0_RS_IDLE 0x20000000 /* idle wait */ ++#define D64_RS0_RS_STOPPED 0x30000000 /* stopped */ ++#define D64_RS0_RS_SUSP 0x40000000 /* suspend pending */ ++ ++#define D64_RS1_AD_MASK 0x0001ffff /* active descriptor */ ++#define D64_RS1_RE_MASK 0xf0000000 /* receive errors */ ++#define D64_RS1_RE_SHIFT 28 ++#define D64_RS1_RE_NOERR 0x00000000 /* no error */ ++#define D64_RS1_RE_DPO 0x10000000 /* descriptor protocol error */ ++#define D64_RS1_RE_DFU 0x20000000 /* data fifo overflow */ ++#define D64_RS1_RE_DTE 0x30000000 /* data transfer error */ ++#define D64_RS1_RE_DESRE 0x40000000 /* descriptor read error */ ++#define D64_RS1_RE_COREE 0x50000000 /* core error */ ++ ++/* fifoaddr */ ++#define D64_FA_OFF_MASK 0xffff /* offset */ ++#define D64_FA_SEL_MASK 0xf0000 /* select */ ++#define D64_FA_SEL_SHIFT 16 ++#define D64_FA_SEL_XDD 0x00000 /* transmit dma data */ ++#define D64_FA_SEL_XDP 0x10000 /* transmit dma pointers */ ++#define D64_FA_SEL_RDD 0x40000 /* receive dma data */ ++#define D64_FA_SEL_RDP 0x50000 /* receive dma pointers */ ++#define D64_FA_SEL_XFD 0x80000 /* transmit fifo data */ ++#define D64_FA_SEL_XFP 0x90000 /* transmit fifo pointers */ ++#define D64_FA_SEL_RFD 0xc0000 /* receive fifo data */ ++#define D64_FA_SEL_RFP 0xd0000 /* receive fifo pointers */ ++#define D64_FA_SEL_RSD 0xe0000 /* receive frame status data */ ++#define D64_FA_SEL_RSP 0xf0000 /* receive frame status pointers */ ++ ++/* descriptor control flags 1 */ ++#define D64_CTRL_COREFLAGS 0x0ff00000 /* core specific flags */ ++#define D64_CTRL1_EOT ((uint32)1 << 28) /* end of descriptor table */ ++#define D64_CTRL1_IOC ((uint32)1 << 29) /* interrupt on completion */ ++#define D64_CTRL1_EOF ((uint32)1 << 30) /* end of frame */ ++#define D64_CTRL1_SOF ((uint32)1 << 31) /* start of frame */ ++ ++/* descriptor control flags 2 */ ++#define D64_CTRL2_BC_MASK 0x00007fff /* buffer byte count. real data len must <= 16KB */ ++#define D64_CTRL2_AE 0x00030000 /* address extension bits */ ++#define D64_CTRL2_AE_SHIFT 16 ++#define D64_CTRL2_PARITY 0x00040000 /* parity bit */ ++ ++/* control flags in the range [27:20] are core-specific and not defined here */ ++#define D64_CTRL_CORE_MASK 0x0ff00000 ++ ++#define D64_RX_FRM_STS_LEN 0x0000ffff /* frame length mask */ ++#define D64_RX_FRM_STS_OVFL 0x00800000 /* RxOverFlow */ ++#define D64_RX_FRM_STS_DSCRCNT 0x0f000000 /* no. of descriptors used - 1, d11corerev >= 22 */ ++#define D64_RX_FRM_STS_DATATYPE 0xf0000000 /* core-dependent data type */ ++ ++/* receive frame status */ ++typedef volatile struct { ++ uint16 len; ++ uint16 flags; ++} dma_rxh_t; ++ ++#endif /* _sbhnddma_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/sbpcmcia.h b/drivers/net/wireless/ap6211/include/sbpcmcia.h +new file mode 100755 +index 0000000..c4e9d46 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sbpcmcia.h +@@ -0,0 +1,113 @@ ++/* ++ * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sbpcmcia.h 326494 2012-04-09 13:29:57Z $ ++ */ ++ ++#ifndef _SBPCMCIA_H ++#define _SBPCMCIA_H ++ ++/* All the addresses that are offsets in attribute space are divided ++ * by two to account for the fact that odd bytes are invalid in ++ * attribute space and our read/write routines make the space appear ++ * as if they didn't exist. Still we want to show the original numbers ++ * as documented in the hnd_pcmcia core manual. ++ */ ++ ++/* PCMCIA Function Configuration Registers */ ++#define PCMCIA_FCR (0x700 / 2) ++ ++#define FCR0_OFF 0 ++#define FCR1_OFF (0x40 / 2) ++#define FCR2_OFF (0x80 / 2) ++#define FCR3_OFF (0xc0 / 2) ++ ++#define PCMCIA_FCR0 (0x700 / 2) ++#define PCMCIA_FCR1 (0x740 / 2) ++#define PCMCIA_FCR2 (0x780 / 2) ++#define PCMCIA_FCR3 (0x7c0 / 2) ++ ++/* Standard PCMCIA FCR registers */ ++ ++#define PCMCIA_COR 0 ++ ++#define COR_RST 0x80 ++#define COR_LEV 0x40 ++#define COR_IRQEN 0x04 ++#define COR_BLREN 0x01 ++#define COR_FUNEN 0x01 ++ ++ ++#define PCICIA_FCSR (2 / 2) ++#define PCICIA_PRR (4 / 2) ++#define PCICIA_SCR (6 / 2) ++#define PCICIA_ESR (8 / 2) ++ ++ ++#define PCM_MEMOFF 0x0000 ++#define F0_MEMOFF 0x1000 ++#define F1_MEMOFF 0x2000 ++#define F2_MEMOFF 0x3000 ++#define F3_MEMOFF 0x4000 ++ ++/* Memory base in the function fcr's */ ++#define MEM_ADDR0 (0x728 / 2) ++#define MEM_ADDR1 (0x72a / 2) ++#define MEM_ADDR2 (0x72c / 2) ++ ++/* PCMCIA base plus Srom access in fcr0: */ ++#define PCMCIA_ADDR0 (0x072e / 2) ++#define PCMCIA_ADDR1 (0x0730 / 2) ++#define PCMCIA_ADDR2 (0x0732 / 2) ++ ++#define MEM_SEG (0x0734 / 2) ++#define SROM_CS (0x0736 / 2) ++#define SROM_DATAL (0x0738 / 2) ++#define SROM_DATAH (0x073a / 2) ++#define SROM_ADDRL (0x073c / 2) ++#define SROM_ADDRH (0x073e / 2) ++#define SROM_INFO2 (0x0772 / 2) /* Corerev >= 2 && <= 5 */ ++#define SROM_INFO (0x07be / 2) /* Corerev >= 6 */ ++ ++/* Values for srom_cs: */ ++#define SROM_IDLE 0 ++#define SROM_WRITE 1 ++#define SROM_READ 2 ++#define SROM_WEN 4 ++#define SROM_WDS 7 ++#define SROM_DONE 8 ++ ++/* Fields in srom_info: */ ++#define SRI_SZ_MASK 0x03 ++#define SRI_BLANK 0x04 ++#define SRI_OTP 0x80 ++ ++ ++/* sbtmstatelow */ ++#define SBTML_INT_ACK 0x40000 /* ack the sb interrupt */ ++#define SBTML_INT_EN 0x20000 /* enable sb interrupt */ ++ ++/* sbtmstatehigh */ ++#define SBTMH_INT_STATUS 0x40000 /* sb interrupt status */ ++ ++#endif /* _SBPCMCIA_H */ +diff --git a/drivers/net/wireless/ap6211/include/sbsdio.h b/drivers/net/wireless/ap6211/include/sbsdio.h +new file mode 100755 +index 0000000..8d0139d +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sbsdio.h +@@ -0,0 +1,188 @@ ++/* ++ * SDIO device core hardware definitions. ++ * sdio is a portion of the pcmcia core in core rev 3 - rev 8 ++ * ++ * SDIO core support 1bit, 4 bit SDIO mode as well as SPI mode. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sbsdio.h 361940 2012-10-10 08:32:12Z $ ++ */ ++ ++#ifndef _SBSDIO_H ++#define _SBSDIO_H ++ ++#define SBSDIO_NUM_FUNCTION 3 /* as of sdiod rev 0, supports 3 functions */ ++ ++/* function 1 miscellaneous registers */ ++#define SBSDIO_SPROM_CS 0x10000 /* sprom command and status */ ++#define SBSDIO_SPROM_INFO 0x10001 /* sprom info register */ ++#define SBSDIO_SPROM_DATA_LOW 0x10002 /* sprom indirect access data byte 0 */ ++#define SBSDIO_SPROM_DATA_HIGH 0x10003 /* sprom indirect access data byte 1 */ ++#define SBSDIO_SPROM_ADDR_LOW 0x10004 /* sprom indirect access addr byte 0 */ ++#define SBSDIO_SPROM_ADDR_HIGH 0x10005 /* sprom indirect access addr byte 0 */ ++#define SBSDIO_CHIP_CTRL_DATA 0x10006 /* xtal_pu (gpio) output */ ++#define SBSDIO_CHIP_CTRL_EN 0x10007 /* xtal_pu (gpio) enable */ ++#define SBSDIO_WATERMARK 0x10008 /* rev < 7, watermark for sdio device */ ++#define SBSDIO_DEVICE_CTL 0x10009 /* control busy signal generation */ ++ ++/* registers introduced in rev 8, some content (mask/bits) defs in sbsdpcmdev.h */ ++#define SBSDIO_FUNC1_SBADDRLOW 0x1000A /* SB Address Window Low (b15) */ ++#define SBSDIO_FUNC1_SBADDRMID 0x1000B /* SB Address Window Mid (b23:b16) */ ++#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C /* SB Address Window High (b31:b24) */ ++#define SBSDIO_FUNC1_FRAMECTRL 0x1000D /* Frame Control (frame term/abort) */ ++#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E /* ChipClockCSR (ALP/HT ctl/status) */ ++#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F /* SdioPullUp (on cmd, d0-d2) */ ++#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019 /* Write Frame Byte Count Low */ ++#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A /* Write Frame Byte Count High */ ++#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B /* Read Frame Byte Count Low */ ++#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C /* Read Frame Byte Count High */ ++#define SBSDIO_FUNC1_MESBUSYCTRL 0x1001D /* MesBusyCtl at 0x1001D (rev 11) */ ++ ++#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */ ++#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001C /* f1 misc register end */ ++ ++/* Sdio Core Rev 12 */ ++#define SBSDIO_FUNC1_WAKEUPCTRL 0x1001E ++#define SBSDIO_FUNC1_WCTRL_ALPWAIT_MASK 0x1 ++#define SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT 0 ++#define SBSDIO_FUNC1_WCTRL_HTWAIT_MASK 0x2 ++#define SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT 1 ++#define SBSDIO_FUNC1_SLEEPCSR 0x1001F ++#define SBSDIO_FUNC1_SLEEPCSR_KSO_MASK 0x1 ++#define SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT 0 ++#define SBSDIO_FUNC1_SLEEPCSR_KSO_EN 1 ++#define SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK 0x2 ++#define SBSDIO_FUNC1_SLEEPCSR_DEVON_SHIFT 1 ++ ++/* SBSDIO_SPROM_CS */ ++#define SBSDIO_SPROM_IDLE 0 ++#define SBSDIO_SPROM_WRITE 1 ++#define SBSDIO_SPROM_READ 2 ++#define SBSDIO_SPROM_WEN 4 ++#define SBSDIO_SPROM_WDS 7 ++#define SBSDIO_SPROM_DONE 8 ++ ++/* SBSDIO_SPROM_INFO */ ++#define SROM_SZ_MASK 0x03 /* SROM size, 1: 4k, 2: 16k */ ++#define SROM_BLANK 0x04 /* depreciated in corerev 6 */ ++#define SROM_OTP 0x80 /* OTP present */ ++ ++/* SBSDIO_CHIP_CTRL */ ++#define SBSDIO_CHIP_CTRL_XTAL 0x01 /* or'd with onchip xtal_pu, ++ * 1: power on oscillator ++ * (for 4318 only) ++ */ ++/* SBSDIO_WATERMARK */ ++#define SBSDIO_WATERMARK_MASK 0x7f /* number of words - 1 for sd device ++ * to wait before sending data to host ++ */ ++ ++/* SBSDIO_MESBUSYCTRL */ ++/* When RX FIFO has less entries than this & MBE is set ++ * => busy signal is asserted between data blocks. ++*/ ++#define SBSDIO_MESBUSYCTRL_MASK 0x7f ++ ++/* SBSDIO_DEVICE_CTL */ ++#define SBSDIO_DEVCTL_SETBUSY 0x01 /* 1: device will assert busy signal when ++ * receiving CMD53 ++ */ ++#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02 /* 1: assertion of sdio interrupt is ++ * synchronous to the sdio clock ++ */ ++#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04 /* 1: mask all interrupts to host ++ * except the chipActive (rev 8) ++ */ ++#define SBSDIO_DEVCTL_PADS_ISO 0x08 /* 1: isolate internal sdio signals, put ++ * external pads in tri-state; requires ++ * sdio bus power cycle to clear (rev 9) ++ */ ++#define SBSDIO_DEVCTL_SB_RST_CTL 0x30 /* Force SD->SB reset mapping (rev 11) */ ++#define SBSDIO_DEVCTL_RST_CORECTL 0x00 /* Determined by CoreControl bit */ ++#define SBSDIO_DEVCTL_RST_BPRESET 0x10 /* Force backplane reset */ ++#define SBSDIO_DEVCTL_RST_NOBPRESET 0x20 /* Force no backplane reset */ ++#define SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK 0x10 /* Enable function 2 tx for each block */ ++ ++ ++/* SBSDIO_FUNC1_CHIPCLKCSR */ ++#define SBSDIO_FORCE_ALP 0x01 /* Force ALP request to backplane */ ++#define SBSDIO_FORCE_HT 0x02 /* Force HT request to backplane */ ++#define SBSDIO_FORCE_ILP 0x04 /* Force ILP request to backplane */ ++#define SBSDIO_ALP_AVAIL_REQ 0x08 /* Make ALP ready (power up xtal) */ ++#define SBSDIO_HT_AVAIL_REQ 0x10 /* Make HT ready (power up PLL) */ ++#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20 /* Squelch clock requests from HW */ ++#define SBSDIO_ALP_AVAIL 0x40 /* Status: ALP is ready */ ++#define SBSDIO_HT_AVAIL 0x80 /* Status: HT is ready */ ++/* In rev8, actual avail bits followed original docs */ ++#define SBSDIO_Rev8_HT_AVAIL 0x40 ++#define SBSDIO_Rev8_ALP_AVAIL 0x80 ++#define SBSDIO_CSR_MASK 0x1F ++ ++#define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL) ++#define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS) ++#define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS) ++#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval)) ++#define SBSDIO_CLKAV(regval, alponly) (SBSDIO_ALPAV(regval) && \ ++ (alponly ? 1 : SBSDIO_HTAV(regval))) ++ ++/* SBSDIO_FUNC1_SDIOPULLUP */ ++#define SBSDIO_PULLUP_D0 0x01 /* Enable D0/MISO pullup */ ++#define SBSDIO_PULLUP_D1 0x02 /* Enable D1/INT# pullup */ ++#define SBSDIO_PULLUP_D2 0x04 /* Enable D2 pullup */ ++#define SBSDIO_PULLUP_CMD 0x08 /* Enable CMD/MOSI pullup */ ++#define SBSDIO_PULLUP_ALL 0x0f /* All valid bits */ ++ ++/* function 1 OCP space */ ++#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF /* sb offset addr is <= 15 bits, 32k */ ++#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000 ++#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000 /* with b15, maps to 32-bit SB access */ ++ ++/* some duplication with sbsdpcmdev.h here */ ++/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */ ++#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid bits in SBADDRLOW */ ++#define SBSDIO_SBADDRMID_MASK 0xff /* Valid bits in SBADDRMID */ ++#define SBSDIO_SBADDRHIGH_MASK 0xffU /* Valid bits in SBADDRHIGH */ ++#define SBSDIO_SBWINDOW_MASK 0xffff8000 /* Address bits from SBADDR regs */ ++ ++/* direct(mapped) cis space */ ++#define SBSDIO_CIS_BASE_COMMON 0x1000 /* MAPPED common CIS address */ ++#define SBSDIO_CIS_SIZE_LIMIT 0x200 /* maximum bytes in one CIS */ ++#define SBSDIO_OTP_CIS_SIZE_LIMIT 0x078 /* maximum bytes OTP CIS */ ++ ++#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF /* cis offset addr is < 17 bits */ ++ ++#define SBSDIO_CIS_MANFID_TUPLE_LEN 6 /* manfid tuple length, include tuple, ++ * link bytes ++ */ ++ ++/* indirect cis access (in sprom) */ ++#define SBSDIO_SPROM_CIS_OFFSET 0x8 /* 8 control bytes first, CIS starts from ++ * 8th byte ++ */ ++ ++#define SBSDIO_BYTEMODE_DATALEN_MAX 64 /* sdio byte mode: maximum length of one ++ * data comamnd ++ */ ++ ++#define SBSDIO_CORE_ADDR_MASK 0x1FFFF /* sdio core function one address mask */ ++ ++#endif /* _SBSDIO_H */ +diff --git a/drivers/net/wireless/ap6211/include/sbsdpcmdev.h b/drivers/net/wireless/ap6211/include/sbsdpcmdev.h +new file mode 100755 +index 0000000..10c7401 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sbsdpcmdev.h +@@ -0,0 +1,295 @@ ++/* ++ * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific ++ * device core support ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sbsdpcmdev.h 347614 2012-07-27 10:24:51Z $ ++ */ ++ ++#ifndef _sbsdpcmdev_h_ ++#define _sbsdpcmdev_h_ ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif /* PAD */ ++ ++ ++typedef volatile struct { ++ dma64regs_t xmt; /* dma tx */ ++ uint32 PAD[2]; ++ dma64regs_t rcv; /* dma rx */ ++ uint32 PAD[2]; ++} dma64p_t; ++ ++/* dma64 sdiod corerev >= 1 */ ++typedef volatile struct { ++ dma64p_t dma64regs[2]; ++ dma64diag_t dmafifo; /* DMA Diagnostic Regs, 0x280-0x28c */ ++ uint32 PAD[92]; ++} sdiodma64_t; ++ ++/* dma32 sdiod corerev == 0 */ ++typedef volatile struct { ++ dma32regp_t dma32regs[2]; /* dma tx & rx, 0x200-0x23c */ ++ dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x240-0x24c */ ++ uint32 PAD[108]; ++} sdiodma32_t; ++ ++/* dma32 regs for pcmcia core */ ++typedef volatile struct { ++ dma32regp_t dmaregs; /* DMA Regs, 0x200-0x21c, rev8 */ ++ dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x220-0x22c */ ++ uint32 PAD[116]; ++} pcmdma32_t; ++ ++/* core registers */ ++typedef volatile struct { ++ uint32 corecontrol; /* CoreControl, 0x000, rev8 */ ++ uint32 corestatus; /* CoreStatus, 0x004, rev8 */ ++ uint32 PAD[1]; ++ uint32 biststatus; /* BistStatus, 0x00c, rev8 */ ++ ++ /* PCMCIA access */ ++ uint16 pcmciamesportaladdr; /* PcmciaMesPortalAddr, 0x010, rev8 */ ++ uint16 PAD[1]; ++ uint16 pcmciamesportalmask; /* PcmciaMesPortalMask, 0x014, rev8 */ ++ uint16 PAD[1]; ++ uint16 pcmciawrframebc; /* PcmciaWrFrameBC, 0x018, rev8 */ ++ uint16 PAD[1]; ++ uint16 pcmciaunderflowtimer; /* PcmciaUnderflowTimer, 0x01c, rev8 */ ++ uint16 PAD[1]; ++ ++ /* interrupt */ ++ uint32 intstatus; /* IntStatus, 0x020, rev8 */ ++ uint32 hostintmask; /* IntHostMask, 0x024, rev8 */ ++ uint32 intmask; /* IntSbMask, 0x028, rev8 */ ++ uint32 sbintstatus; /* SBIntStatus, 0x02c, rev8 */ ++ uint32 sbintmask; /* SBIntMask, 0x030, rev8 */ ++ uint32 funcintmask; /* SDIO Function Interrupt Mask, SDIO rev4 */ ++ uint32 PAD[2]; ++ uint32 tosbmailbox; /* ToSBMailbox, 0x040, rev8 */ ++ uint32 tohostmailbox; /* ToHostMailbox, 0x044, rev8 */ ++ uint32 tosbmailboxdata; /* ToSbMailboxData, 0x048, rev8 */ ++ uint32 tohostmailboxdata; /* ToHostMailboxData, 0x04c, rev8 */ ++ ++ /* synchronized access to registers in SDIO clock domain */ ++ uint32 sdioaccess; /* SdioAccess, 0x050, rev8 */ ++ uint32 PAD[3]; ++ ++ /* PCMCIA frame control */ ++ uint8 pcmciaframectrl; /* pcmciaFrameCtrl, 0x060, rev8 */ ++ uint8 PAD[3]; ++ uint8 pcmciawatermark; /* pcmciaWaterMark, 0x064, rev8 */ ++ uint8 PAD[155]; ++ ++ /* interrupt batching control */ ++ uint32 intrcvlazy; /* IntRcvLazy, 0x100, rev8 */ ++ uint32 PAD[3]; ++ ++ /* counters */ ++ uint32 cmd52rd; /* Cmd52RdCount, 0x110, rev8, SDIO: cmd52 reads */ ++ uint32 cmd52wr; /* Cmd52WrCount, 0x114, rev8, SDIO: cmd52 writes */ ++ uint32 cmd53rd; /* Cmd53RdCount, 0x118, rev8, SDIO: cmd53 reads */ ++ uint32 cmd53wr; /* Cmd53WrCount, 0x11c, rev8, SDIO: cmd53 writes */ ++ uint32 abort; /* AbortCount, 0x120, rev8, SDIO: aborts */ ++ uint32 datacrcerror; /* DataCrcErrorCount, 0x124, rev8, SDIO: frames w/bad CRC */ ++ uint32 rdoutofsync; /* RdOutOfSyncCount, 0x128, rev8, SDIO/PCMCIA: Rd Frm OOS */ ++ uint32 wroutofsync; /* RdOutOfSyncCount, 0x12c, rev8, SDIO/PCMCIA: Wr Frm OOS */ ++ uint32 writebusy; /* WriteBusyCount, 0x130, rev8, SDIO: dev asserted "busy" */ ++ uint32 readwait; /* ReadWaitCount, 0x134, rev8, SDIO: read: no data avail */ ++ uint32 readterm; /* ReadTermCount, 0x138, rev8, SDIO: rd frm terminates */ ++ uint32 writeterm; /* WriteTermCount, 0x13c, rev8, SDIO: wr frm terminates */ ++ uint32 PAD[40]; ++ uint32 clockctlstatus; /* ClockCtlStatus, 0x1e0, rev8 */ ++ uint32 PAD[7]; ++ ++ /* DMA engines */ ++ volatile union { ++ pcmdma32_t pcm32; ++ sdiodma32_t sdiod32; ++ sdiodma64_t sdiod64; ++ } dma; ++ ++ /* SDIO/PCMCIA CIS region */ ++ char cis[512]; /* 512 byte CIS, 0x400-0x5ff, rev6 */ ++ ++ /* PCMCIA function control registers */ ++ char pcmciafcr[256]; /* PCMCIA FCR, 0x600-6ff, rev6 */ ++ uint16 PAD[55]; ++ ++ /* PCMCIA backplane access */ ++ uint16 backplanecsr; /* BackplaneCSR, 0x76E, rev6 */ ++ uint16 backplaneaddr0; /* BackplaneAddr0, 0x770, rev6 */ ++ uint16 backplaneaddr1; /* BackplaneAddr1, 0x772, rev6 */ ++ uint16 backplaneaddr2; /* BackplaneAddr2, 0x774, rev6 */ ++ uint16 backplaneaddr3; /* BackplaneAddr3, 0x776, rev6 */ ++ uint16 backplanedata0; /* BackplaneData0, 0x778, rev6 */ ++ uint16 backplanedata1; /* BackplaneData1, 0x77a, rev6 */ ++ uint16 backplanedata2; /* BackplaneData2, 0x77c, rev6 */ ++ uint16 backplanedata3; /* BackplaneData3, 0x77e, rev6 */ ++ uint16 PAD[31]; ++ ++ /* sprom "size" & "blank" info */ ++ uint16 spromstatus; /* SPROMStatus, 0x7BE, rev2 */ ++ uint32 PAD[464]; ++ ++ /* Sonics SiliconBackplane registers */ ++ sbconfig_t sbconfig; /* SbConfig Regs, 0xf00-0xfff, rev8 */ ++} sdpcmd_regs_t; ++ ++/* corecontrol */ ++#define CC_CISRDY (1 << 0) /* CIS Ready */ ++#define CC_BPRESEN (1 << 1) /* CCCR RES signal causes backplane reset */ ++#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */ ++#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation bit (rev 11) */ ++#define CC_XMTDATAAVAIL_MODE (1 << 4) /* data avail generates an interrupt */ ++#define CC_XMTDATAAVAIL_CTRL (1 << 5) /* data avail interrupt ctrl */ ++ ++/* corestatus */ ++#define CS_PCMCIAMODE (1 << 0) /* Device Mode; 0=SDIO, 1=PCMCIA */ ++#define CS_SMARTDEV (1 << 1) /* 1=smartDev enabled */ ++#define CS_F2ENABLED (1 << 2) /* 1=host has enabled the device */ ++ ++#define PCMCIA_MES_PA_MASK 0x7fff /* PCMCIA Message Portal Address Mask */ ++#define PCMCIA_MES_PM_MASK 0x7fff /* PCMCIA Message Portal Mask Mask */ ++#define PCMCIA_WFBC_MASK 0xffff /* PCMCIA Write Frame Byte Count Mask */ ++#define PCMCIA_UT_MASK 0x07ff /* PCMCIA Underflow Timer Mask */ ++ ++/* intstatus */ ++#define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */ ++#define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */ ++#define I_SMB_SW2 (1 << 2) /* To SB Mail S/W interrupt 2 */ ++#define I_SMB_SW3 (1 << 3) /* To SB Mail S/W interrupt 3 */ ++#define I_SMB_SW_MASK 0x0000000f /* To SB Mail S/W interrupts mask */ ++#define I_SMB_SW_SHIFT 0 /* To SB Mail S/W interrupts shift */ ++#define I_HMB_SW0 (1 << 4) /* To Host Mail S/W interrupt 0 */ ++#define I_HMB_SW1 (1 << 5) /* To Host Mail S/W interrupt 1 */ ++#define I_HMB_SW2 (1 << 6) /* To Host Mail S/W interrupt 2 */ ++#define I_HMB_SW3 (1 << 7) /* To Host Mail S/W interrupt 3 */ ++#define I_HMB_SW_MASK 0x000000f0 /* To Host Mail S/W interrupts mask */ ++#define I_HMB_SW_SHIFT 4 /* To Host Mail S/W interrupts shift */ ++#define I_WR_OOSYNC (1 << 8) /* Write Frame Out Of Sync */ ++#define I_RD_OOSYNC (1 << 9) /* Read Frame Out Of Sync */ ++#define I_PC (1 << 10) /* descriptor error */ ++#define I_PD (1 << 11) /* data error */ ++#define I_DE (1 << 12) /* Descriptor protocol Error */ ++#define I_RU (1 << 13) /* Receive descriptor Underflow */ ++#define I_RO (1 << 14) /* Receive fifo Overflow */ ++#define I_XU (1 << 15) /* Transmit fifo Underflow */ ++#define I_RI (1 << 16) /* Receive Interrupt */ ++#define I_BUSPWR (1 << 17) /* SDIO Bus Power Change (rev 9) */ ++#define I_XMTDATA_AVAIL (1 << 23) /* bits in fifo */ ++#define I_XI (1 << 24) /* Transmit Interrupt */ ++#define I_RF_TERM (1 << 25) /* Read Frame Terminate */ ++#define I_WF_TERM (1 << 26) /* Write Frame Terminate */ ++#define I_PCMCIA_XU (1 << 27) /* PCMCIA Transmit FIFO Underflow */ ++#define I_SBINT (1 << 28) /* sbintstatus Interrupt */ ++#define I_CHIPACTIVE (1 << 29) /* chip transitioned from doze to active state */ ++#define I_SRESET (1 << 30) /* CCCR RES interrupt */ ++#define I_IOE2 (1U << 31) /* CCCR IOE2 Bit Changed */ ++#define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU) /* DMA Errors */ ++#define I_DMA (I_RI | I_XI | I_ERRORS) ++ ++/* sbintstatus */ ++#define I_SB_SERR (1 << 8) /* Backplane SError (write) */ ++#define I_SB_RESPERR (1 << 9) /* Backplane Response Error (read) */ ++#define I_SB_SPROMERR (1 << 10) /* Error accessing the sprom */ ++ ++/* sdioaccess */ ++#define SDA_DATA_MASK 0x000000ff /* Read/Write Data Mask */ ++#define SDA_ADDR_MASK 0x000fff00 /* Read/Write Address Mask */ ++#define SDA_ADDR_SHIFT 8 /* Read/Write Address Shift */ ++#define SDA_WRITE 0x01000000 /* Write bit */ ++#define SDA_READ 0x00000000 /* Write bit cleared for Read */ ++#define SDA_BUSY 0x80000000 /* Busy bit */ ++ ++/* sdioaccess-accessible register address spaces */ ++#define SDA_CCCR_SPACE 0x000 /* sdioAccess CCCR register space */ ++#define SDA_F1_FBR_SPACE 0x100 /* sdioAccess F1 FBR register space */ ++#define SDA_F2_FBR_SPACE 0x200 /* sdioAccess F2 FBR register space */ ++#define SDA_F1_REG_SPACE 0x300 /* sdioAccess F1 core-specific register space */ ++ ++/* SDA_F1_REG_SPACE sdioaccess-accessible F1 reg space register offsets */ ++#define SDA_CHIPCONTROLDATA 0x006 /* ChipControlData */ ++#define SDA_CHIPCONTROLENAB 0x007 /* ChipControlEnable */ ++#define SDA_F2WATERMARK 0x008 /* Function 2 Watermark */ ++#define SDA_DEVICECONTROL 0x009 /* DeviceControl */ ++#define SDA_SBADDRLOW 0x00a /* SbAddrLow */ ++#define SDA_SBADDRMID 0x00b /* SbAddrMid */ ++#define SDA_SBADDRHIGH 0x00c /* SbAddrHigh */ ++#define SDA_FRAMECTRL 0x00d /* FrameCtrl */ ++#define SDA_CHIPCLOCKCSR 0x00e /* ChipClockCSR */ ++#define SDA_SDIOPULLUP 0x00f /* SdioPullUp */ ++#define SDA_SDIOWRFRAMEBCLOW 0x019 /* SdioWrFrameBCLow */ ++#define SDA_SDIOWRFRAMEBCHIGH 0x01a /* SdioWrFrameBCHigh */ ++#define SDA_SDIORDFRAMEBCLOW 0x01b /* SdioRdFrameBCLow */ ++#define SDA_SDIORDFRAMEBCHIGH 0x01c /* SdioRdFrameBCHigh */ ++ ++/* SDA_F2WATERMARK */ ++#define SDA_F2WATERMARK_MASK 0x7f /* F2Watermark Mask */ ++ ++/* SDA_SBADDRLOW */ ++#define SDA_SBADDRLOW_MASK 0x80 /* SbAddrLow Mask */ ++ ++/* SDA_SBADDRMID */ ++#define SDA_SBADDRMID_MASK 0xff /* SbAddrMid Mask */ ++ ++/* SDA_SBADDRHIGH */ ++#define SDA_SBADDRHIGH_MASK 0xff /* SbAddrHigh Mask */ ++ ++/* SDA_FRAMECTRL */ ++#define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */ ++#define SFC_WF_TERM (1 << 1) /* Write Frame Terminate */ ++#define SFC_CRC4WOOS (1 << 2) /* HW reports CRC error for write out of sync */ ++#define SFC_ABORTALL (1 << 3) /* Abort cancels all in-progress frames */ ++ ++/* pcmciaframectrl */ ++#define PFC_RF_TERM (1 << 0) /* Read Frame Terminate */ ++#define PFC_WF_TERM (1 << 1) /* Write Frame Terminate */ ++ ++/* intrcvlazy */ ++#define IRL_TO_MASK 0x00ffffff /* timeout */ ++#define IRL_FC_MASK 0xff000000 /* frame count */ ++#define IRL_FC_SHIFT 24 /* frame count */ ++ ++/* rx header */ ++typedef volatile struct { ++ uint16 len; ++ uint16 flags; ++} sdpcmd_rxh_t; ++ ++/* rx header flags */ ++#define RXF_CRC 0x0001 /* CRC error detected */ ++#define RXF_WOOS 0x0002 /* write frame out of sync */ ++#define RXF_WF_TERM 0x0004 /* write frame terminated */ ++#define RXF_ABORT 0x0008 /* write frame aborted */ ++#define RXF_DISCARD (RXF_CRC | RXF_WOOS | RXF_WF_TERM | RXF_ABORT) /* bad frame */ ++ ++/* HW frame tag */ ++#define SDPCM_FRAMETAG_LEN 4 /* HW frametag: 2 bytes len, 2 bytes check val */ ++ ++#define SDPCM_HWEXT_LEN 8 ++ ++#endif /* _sbsdpcmdev_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/sbsocram.h b/drivers/net/wireless/ap6211/include/sbsocram.h +new file mode 100755 +index 0000000..6455f2b +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sbsocram.h +@@ -0,0 +1,199 @@ ++/* ++ * BCM47XX Sonics SiliconBackplane embedded ram core ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sbsocram.h 271781 2011-07-13 20:00:06Z $ ++ */ ++ ++#ifndef _SBSOCRAM_H ++#define _SBSOCRAM_H ++ ++#ifndef _LANGUAGE_ASSEMBLY ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif /* PAD */ ++ ++/* Memcsocram core registers */ ++typedef volatile struct sbsocramregs { ++ uint32 coreinfo; ++ uint32 bwalloc; ++ uint32 extracoreinfo; ++ uint32 biststat; ++ uint32 bankidx; ++ uint32 standbyctrl; ++ ++ uint32 errlogstatus; /* rev 6 */ ++ uint32 errlogaddr; /* rev 6 */ ++ /* used for patching rev 3 & 5 */ ++ uint32 cambankidx; ++ uint32 cambankstandbyctrl; ++ uint32 cambankpatchctrl; ++ uint32 cambankpatchtblbaseaddr; ++ uint32 cambankcmdreg; ++ uint32 cambankdatareg; ++ uint32 cambankmaskreg; ++ uint32 PAD[1]; ++ uint32 bankinfo; /* corev 8 */ ++ uint32 PAD[15]; ++ uint32 extmemconfig; ++ uint32 extmemparitycsr; ++ uint32 extmemparityerrdata; ++ uint32 extmemparityerrcnt; ++ uint32 extmemwrctrlandsize; ++ uint32 PAD[84]; ++ uint32 workaround; ++ uint32 pwrctl; /* corerev >= 2 */ ++ uint32 PAD[133]; ++ uint32 sr_control; /* corerev >= 15 */ ++ uint32 sr_status; /* corerev >= 15 */ ++ uint32 sr_address; /* corerev >= 15 */ ++ uint32 sr_data; /* corerev >= 15 */ ++} sbsocramregs_t; ++ ++#endif /* _LANGUAGE_ASSEMBLY */ ++ ++/* Register offsets */ ++#define SR_COREINFO 0x00 ++#define SR_BWALLOC 0x04 ++#define SR_BISTSTAT 0x0c ++#define SR_BANKINDEX 0x10 ++#define SR_BANKSTBYCTL 0x14 ++#define SR_PWRCTL 0x1e8 ++ ++/* Coreinfo register */ ++#define SRCI_PT_MASK 0x00070000 /* corerev >= 6; port type[18:16] */ ++#define SRCI_PT_SHIFT 16 ++/* port types : SRCI_PT__ */ ++#define SRCI_PT_OCP_OCP 0 ++#define SRCI_PT_AXI_OCP 1 ++#define SRCI_PT_ARM7AHB_OCP 2 ++#define SRCI_PT_CM3AHB_OCP 3 ++#define SRCI_PT_AXI_AXI 4 ++#define SRCI_PT_AHB_AXI 5 ++/* corerev >= 3 */ ++#define SRCI_LSS_MASK 0x00f00000 ++#define SRCI_LSS_SHIFT 20 ++#define SRCI_LRS_MASK 0x0f000000 ++#define SRCI_LRS_SHIFT 24 ++ ++/* In corerev 0, the memory size is 2 to the power of the ++ * base plus 16 plus to the contents of the memsize field plus 1. ++ */ ++#define SRCI_MS0_MASK 0xf ++#define SR_MS0_BASE 16 ++ ++/* ++ * In corerev 1 the bank size is 2 ^ the bank size field plus 14, ++ * the memory size is number of banks times bank size. ++ * The same applies to rom size. ++ */ ++#define SRCI_ROMNB_MASK 0xf000 ++#define SRCI_ROMNB_SHIFT 12 ++#define SRCI_ROMBSZ_MASK 0xf00 ++#define SRCI_ROMBSZ_SHIFT 8 ++#define SRCI_SRNB_MASK 0xf0 ++#define SRCI_SRNB_SHIFT 4 ++#define SRCI_SRBSZ_MASK 0xf ++#define SRCI_SRBSZ_SHIFT 0 ++ ++#define SR_BSZ_BASE 14 ++ ++/* Standby control register */ ++#define SRSC_SBYOVR_MASK 0x80000000 ++#define SRSC_SBYOVR_SHIFT 31 ++#define SRSC_SBYOVRVAL_MASK 0x60000000 ++#define SRSC_SBYOVRVAL_SHIFT 29 ++#define SRSC_SBYEN_MASK 0x01000000 /* rev >= 3 */ ++#define SRSC_SBYEN_SHIFT 24 ++ ++/* Power control register */ ++#define SRPC_PMU_STBYDIS_MASK 0x00000010 /* rev >= 3 */ ++#define SRPC_PMU_STBYDIS_SHIFT 4 ++#define SRPC_STBYOVRVAL_MASK 0x00000008 ++#define SRPC_STBYOVRVAL_SHIFT 3 ++#define SRPC_STBYOVR_MASK 0x00000007 ++#define SRPC_STBYOVR_SHIFT 0 ++ ++/* Extra core capability register */ ++#define SRECC_NUM_BANKS_MASK 0x000000F0 ++#define SRECC_NUM_BANKS_SHIFT 4 ++#define SRECC_BANKSIZE_MASK 0x0000000F ++#define SRECC_BANKSIZE_SHIFT 0 ++ ++#define SRECC_BANKSIZE(value) (1 << (value)) ++ ++/* CAM bank patch control */ ++#define SRCBPC_PATCHENABLE 0x80000000 ++ ++#define SRP_ADDRESS 0x0001FFFC ++#define SRP_VALID 0x8000 ++ ++/* CAM bank command reg */ ++#define SRCMD_WRITE 0x00020000 ++#define SRCMD_READ 0x00010000 ++#define SRCMD_DONE 0x80000000 ++ ++#define SRCMD_DONE_DLY 1000 ++ ++/* bankidx and bankinfo reg defines corerev >= 8 */ ++#define SOCRAM_BANKINFO_SZMASK 0x7f ++#define SOCRAM_BANKIDX_ROM_MASK 0x100 ++ ++#define SOCRAM_BANKIDX_MEMTYPE_SHIFT 8 ++/* socram bankinfo memtype */ ++#define SOCRAM_MEMTYPE_RAM 0 ++#define SOCRAM_MEMTYPE_R0M 1 ++#define SOCRAM_MEMTYPE_DEVRAM 2 ++ ++#define SOCRAM_BANKINFO_REG 0x40 ++#define SOCRAM_BANKIDX_REG 0x10 ++#define SOCRAM_BANKINFO_STDBY_MASK 0x400 ++#define SOCRAM_BANKINFO_STDBY_TIMER 0x800 ++ ++/* bankinfo rev >= 10 */ ++#define SOCRAM_BANKINFO_DEVRAMSEL_SHIFT 13 ++#define SOCRAM_BANKINFO_DEVRAMSEL_MASK 0x2000 ++#define SOCRAM_BANKINFO_DEVRAMPRO_SHIFT 14 ++#define SOCRAM_BANKINFO_DEVRAMPRO_MASK 0x4000 ++#define SOCRAM_BANKINFO_SLPSUPP_SHIFT 15 ++#define SOCRAM_BANKINFO_SLPSUPP_MASK 0x8000 ++#define SOCRAM_BANKINFO_RETNTRAM_SHIFT 16 ++#define SOCRAM_BANKINFO_RETNTRAM_MASK 0x00010000 ++#define SOCRAM_BANKINFO_PDASZ_SHIFT 17 ++#define SOCRAM_BANKINFO_PDASZ_MASK 0x003E0000 ++#define SOCRAM_BANKINFO_DEVRAMREMAP_SHIFT 24 ++#define SOCRAM_BANKINFO_DEVRAMREMAP_MASK 0x01000000 ++ ++/* extracoreinfo register */ ++#define SOCRAM_DEVRAMBANK_MASK 0xF000 ++#define SOCRAM_DEVRAMBANK_SHIFT 12 ++ ++/* bank info to calculate bank size */ ++#define SOCRAM_BANKINFO_SZBASE 8192 ++#define SOCRAM_BANKSIZE_SHIFT 13 /* SOCRAM_BANKINFO_SZBASE */ ++ ++ ++#endif /* _SBSOCRAM_H */ +diff --git a/drivers/net/wireless/ap6211/include/sdio.h b/drivers/net/wireless/ap6211/include/sdio.h +new file mode 100755 +index 0000000..b8eee1f +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sdio.h +@@ -0,0 +1,617 @@ ++/* ++ * SDIO spec header file ++ * Protocol and standard (common) device definitions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sdio.h 308973 2012-01-18 04:19:34Z $ ++ */ ++ ++#ifndef _SDIO_H ++#define _SDIO_H ++ ++ ++/* CCCR structure for function 0 */ ++typedef volatile struct { ++ uint8 cccr_sdio_rev; /* RO, cccr and sdio revision */ ++ uint8 sd_rev; /* RO, sd spec revision */ ++ uint8 io_en; /* I/O enable */ ++ uint8 io_rdy; /* I/O ready reg */ ++ uint8 intr_ctl; /* Master and per function interrupt enable control */ ++ uint8 intr_status; /* RO, interrupt pending status */ ++ uint8 io_abort; /* read/write abort or reset all functions */ ++ uint8 bus_inter; /* bus interface control */ ++ uint8 capability; /* RO, card capability */ ++ ++ uint8 cis_base_low; /* 0x9 RO, common CIS base address, LSB */ ++ uint8 cis_base_mid; ++ uint8 cis_base_high; /* 0xB RO, common CIS base address, MSB */ ++ ++ /* suspend/resume registers */ ++ uint8 bus_suspend; /* 0xC */ ++ uint8 func_select; /* 0xD */ ++ uint8 exec_flag; /* 0xE */ ++ uint8 ready_flag; /* 0xF */ ++ ++ uint8 fn0_blk_size[2]; /* 0x10(LSB), 0x11(MSB) */ ++ ++ uint8 power_control; /* 0x12 (SDIO version 1.10) */ ++ ++ uint8 speed_control; /* 0x13 */ ++} sdio_regs_t; ++ ++/* SDIO Device CCCR offsets */ ++#define SDIOD_CCCR_REV 0x00 ++#define SDIOD_CCCR_SDREV 0x01 ++#define SDIOD_CCCR_IOEN 0x02 ++#define SDIOD_CCCR_IORDY 0x03 ++#define SDIOD_CCCR_INTEN 0x04 ++#define SDIOD_CCCR_INTPEND 0x05 ++#define SDIOD_CCCR_IOABORT 0x06 ++#define SDIOD_CCCR_BICTRL 0x07 ++#define SDIOD_CCCR_CAPABLITIES 0x08 ++#define SDIOD_CCCR_CISPTR_0 0x09 ++#define SDIOD_CCCR_CISPTR_1 0x0A ++#define SDIOD_CCCR_CISPTR_2 0x0B ++#define SDIOD_CCCR_BUSSUSP 0x0C ++#define SDIOD_CCCR_FUNCSEL 0x0D ++#define SDIOD_CCCR_EXECFLAGS 0x0E ++#define SDIOD_CCCR_RDYFLAGS 0x0F ++#define SDIOD_CCCR_BLKSIZE_0 0x10 ++#define SDIOD_CCCR_BLKSIZE_1 0x11 ++#define SDIOD_CCCR_POWER_CONTROL 0x12 ++#define SDIOD_CCCR_SPEED_CONTROL 0x13 ++#define SDIOD_CCCR_UHSI_SUPPORT 0x14 ++#define SDIOD_CCCR_DRIVER_STRENGTH 0x15 ++#define SDIOD_CCCR_INTR_EXTN 0x16 ++ ++/* Broadcom extensions (corerev >= 1) */ ++#define SDIOD_CCCR_BRCM_CARDCAP 0xf0 ++#define SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT 0x02 ++#define SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT 0x04 ++#define SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC 0x08 ++#define SDIOD_CCCR_BRCM_CARDCTL 0xf1 ++#define SDIOD_CCCR_BRCM_SEPINT 0xf2 ++ ++/* cccr_sdio_rev */ ++#define SDIO_REV_SDIOID_MASK 0xf0 /* SDIO spec revision number */ ++#define SDIO_REV_CCCRID_MASK 0x0f /* CCCR format version number */ ++ ++/* sd_rev */ ++#define SD_REV_PHY_MASK 0x0f /* SD format version number */ ++ ++/* io_en */ ++#define SDIO_FUNC_ENABLE_1 0x02 /* function 1 I/O enable */ ++#define SDIO_FUNC_ENABLE_2 0x04 /* function 2 I/O enable */ ++ ++/* io_rdys */ ++#define SDIO_FUNC_READY_1 0x02 /* function 1 I/O ready */ ++#define SDIO_FUNC_READY_2 0x04 /* function 2 I/O ready */ ++ ++/* intr_ctl */ ++#define INTR_CTL_MASTER_EN 0x1 /* interrupt enable master */ ++#define INTR_CTL_FUNC1_EN 0x2 /* interrupt enable for function 1 */ ++#define INTR_CTL_FUNC2_EN 0x4 /* interrupt enable for function 2 */ ++ ++/* intr_status */ ++#define INTR_STATUS_FUNC1 0x2 /* interrupt pending for function 1 */ ++#define INTR_STATUS_FUNC2 0x4 /* interrupt pending for function 2 */ ++ ++/* io_abort */ ++#define IO_ABORT_RESET_ALL 0x08 /* I/O card reset */ ++#define IO_ABORT_FUNC_MASK 0x07 /* abort selction: function x */ ++ ++/* bus_inter */ ++#define BUS_CARD_DETECT_DIS 0x80 /* Card Detect disable */ ++#define BUS_SPI_CONT_INTR_CAP 0x40 /* support continuous SPI interrupt */ ++#define BUS_SPI_CONT_INTR_EN 0x20 /* continuous SPI interrupt enable */ ++#define BUS_SD_DATA_WIDTH_MASK 0x03 /* bus width mask */ ++#define BUS_SD_DATA_WIDTH_4BIT 0x02 /* bus width 4-bit mode */ ++#define BUS_SD_DATA_WIDTH_1BIT 0x00 /* bus width 1-bit mode */ ++ ++/* capability */ ++#define SDIO_CAP_4BLS 0x80 /* 4-bit support for low speed card */ ++#define SDIO_CAP_LSC 0x40 /* low speed card */ ++#define SDIO_CAP_E4MI 0x20 /* enable interrupt between block of data in 4-bit mode */ ++#define SDIO_CAP_S4MI 0x10 /* support interrupt between block of data in 4-bit mode */ ++#define SDIO_CAP_SBS 0x08 /* support suspend/resume */ ++#define SDIO_CAP_SRW 0x04 /* support read wait */ ++#define SDIO_CAP_SMB 0x02 /* support multi-block transfer */ ++#define SDIO_CAP_SDC 0x01 /* Support Direct commands during multi-byte transfer */ ++ ++/* power_control */ ++#define SDIO_POWER_SMPC 0x01 /* supports master power control (RO) */ ++#define SDIO_POWER_EMPC 0x02 /* enable master power control (allow > 200mA) (RW) */ ++ ++/* speed_control (control device entry into high-speed clocking mode) */ ++#define SDIO_SPEED_SHS 0x01 /* supports high-speed [clocking] mode (RO) */ ++#define SDIO_SPEED_EHS 0x02 /* enable high-speed [clocking] mode (RW) */ ++ ++/* for setting bus speed in card: 0x13h */ ++#define SDIO_BUS_SPEED_UHSISEL_M BITFIELD_MASK(3) ++#define SDIO_BUS_SPEED_UHSISEL_S 1 ++ ++/* for getting bus speed cap in card: 0x14h */ ++#define SDIO_BUS_SPEED_UHSICAP_M BITFIELD_MASK(3) ++#define SDIO_BUS_SPEED_UHSICAP_S 0 ++ ++/* for getting driver type CAP in card: 0x15h */ ++#define SDIO_BUS_DRVR_TYPE_CAP_M BITFIELD_MASK(3) ++#define SDIO_BUS_DRVR_TYPE_CAP_S 0 ++ ++/* for setting driver type selection in card: 0x15h */ ++#define SDIO_BUS_DRVR_TYPE_SEL_M BITFIELD_MASK(2) ++#define SDIO_BUS_DRVR_TYPE_SEL_S 4 ++ ++/* for getting async int support in card: 0x16h */ ++#define SDIO_BUS_ASYNCINT_CAP_M BITFIELD_MASK(1) ++#define SDIO_BUS_ASYNCINT_CAP_S 0 ++ ++/* for setting async int selection in card: 0x16h */ ++#define SDIO_BUS_ASYNCINT_SEL_M BITFIELD_MASK(1) ++#define SDIO_BUS_ASYNCINT_SEL_S 1 ++ ++/* brcm sepint */ ++#define SDIO_SEPINT_MASK 0x01 /* route sdpcmdev intr onto separate pad (chip-specific) */ ++#define SDIO_SEPINT_OE 0x02 /* 1 asserts output enable for above pad */ ++#define SDIO_SEPINT_ACT_HI 0x04 /* use active high interrupt level instead of active low */ ++ ++/* FBR structure for function 1-7, FBR addresses and register offsets */ ++typedef volatile struct { ++ uint8 devctr; /* device interface, CSA control */ ++ uint8 ext_dev; /* extended standard I/O device type code */ ++ uint8 pwr_sel; /* power selection support */ ++ uint8 PAD[6]; /* reserved */ ++ ++ uint8 cis_low; /* CIS LSB */ ++ uint8 cis_mid; ++ uint8 cis_high; /* CIS MSB */ ++ uint8 csa_low; /* code storage area, LSB */ ++ uint8 csa_mid; ++ uint8 csa_high; /* code storage area, MSB */ ++ uint8 csa_dat_win; /* data access window to function */ ++ ++ uint8 fnx_blk_size[2]; /* block size, little endian */ ++} sdio_fbr_t; ++ ++/* Maximum number of I/O funcs */ ++#define SDIOD_MAX_FUNCS 8 ++#define SDIOD_MAX_IOFUNCS 7 ++ ++/* SDIO Device FBR Start Address */ ++#define SDIOD_FBR_STARTADDR 0x100 ++ ++/* SDIO Device FBR Size */ ++#define SDIOD_FBR_SIZE 0x100 ++ ++/* Macro to calculate FBR register base */ ++#define SDIOD_FBR_BASE(n) ((n) * 0x100) ++ ++/* Function register offsets */ ++#define SDIOD_FBR_DEVCTR 0x00 /* basic info for function */ ++#define SDIOD_FBR_EXT_DEV 0x01 /* extended I/O device code */ ++#define SDIOD_FBR_PWR_SEL 0x02 /* power selection bits */ ++ ++/* SDIO Function CIS ptr offset */ ++#define SDIOD_FBR_CISPTR_0 0x09 ++#define SDIOD_FBR_CISPTR_1 0x0A ++#define SDIOD_FBR_CISPTR_2 0x0B ++ ++/* Code Storage Area pointer */ ++#define SDIOD_FBR_CSA_ADDR_0 0x0C ++#define SDIOD_FBR_CSA_ADDR_1 0x0D ++#define SDIOD_FBR_CSA_ADDR_2 0x0E ++#define SDIOD_FBR_CSA_DATA 0x0F ++ ++/* SDIO Function I/O Block Size */ ++#define SDIOD_FBR_BLKSIZE_0 0x10 ++#define SDIOD_FBR_BLKSIZE_1 0x11 ++ ++/* devctr */ ++#define SDIOD_FBR_DEVCTR_DIC 0x0f /* device interface code */ ++#define SDIOD_FBR_DECVTR_CSA 0x40 /* CSA support flag */ ++#define SDIOD_FBR_DEVCTR_CSA_EN 0x80 /* CSA enabled */ ++/* interface codes */ ++#define SDIOD_DIC_NONE 0 /* SDIO standard interface is not supported */ ++#define SDIOD_DIC_UART 1 ++#define SDIOD_DIC_BLUETOOTH_A 2 ++#define SDIOD_DIC_BLUETOOTH_B 3 ++#define SDIOD_DIC_GPS 4 ++#define SDIOD_DIC_CAMERA 5 ++#define SDIOD_DIC_PHS 6 ++#define SDIOD_DIC_WLAN 7 ++#define SDIOD_DIC_EXT 0xf /* extended device interface, read ext_dev register */ ++ ++/* pwr_sel */ ++#define SDIOD_PWR_SEL_SPS 0x01 /* supports power selection */ ++#define SDIOD_PWR_SEL_EPS 0x02 /* enable power selection (low-current mode) */ ++ ++/* misc defines */ ++#define SDIO_FUNC_0 0 ++#define SDIO_FUNC_1 1 ++#define SDIO_FUNC_2 2 ++#define SDIO_FUNC_3 3 ++#define SDIO_FUNC_4 4 ++#define SDIO_FUNC_5 5 ++#define SDIO_FUNC_6 6 ++#define SDIO_FUNC_7 7 ++ ++#define SD_CARD_TYPE_UNKNOWN 0 /* bad type or unrecognized */ ++#define SD_CARD_TYPE_IO 1 /* IO only card */ ++#define SD_CARD_TYPE_MEMORY 2 /* memory only card */ ++#define SD_CARD_TYPE_COMBO 3 /* IO and memory combo card */ ++ ++#define SDIO_MAX_BLOCK_SIZE 2048 /* maximum block size for block mode operation */ ++#define SDIO_MIN_BLOCK_SIZE 1 /* minimum block size for block mode operation */ ++ ++/* Card registers: status bit position */ ++#define CARDREG_STATUS_BIT_OUTOFRANGE 31 ++#define CARDREG_STATUS_BIT_COMCRCERROR 23 ++#define CARDREG_STATUS_BIT_ILLEGALCOMMAND 22 ++#define CARDREG_STATUS_BIT_ERROR 19 ++#define CARDREG_STATUS_BIT_IOCURRENTSTATE3 12 ++#define CARDREG_STATUS_BIT_IOCURRENTSTATE2 11 ++#define CARDREG_STATUS_BIT_IOCURRENTSTATE1 10 ++#define CARDREG_STATUS_BIT_IOCURRENTSTATE0 9 ++#define CARDREG_STATUS_BIT_FUN_NUM_ERROR 4 ++ ++ ++ ++#define SD_CMD_GO_IDLE_STATE 0 /* mandatory for SDIO */ ++#define SD_CMD_SEND_OPCOND 1 ++#define SD_CMD_MMC_SET_RCA 3 ++#define SD_CMD_IO_SEND_OP_COND 5 /* mandatory for SDIO */ ++#define SD_CMD_SELECT_DESELECT_CARD 7 ++#define SD_CMD_SEND_CSD 9 ++#define SD_CMD_SEND_CID 10 ++#define SD_CMD_STOP_TRANSMISSION 12 ++#define SD_CMD_SEND_STATUS 13 ++#define SD_CMD_GO_INACTIVE_STATE 15 ++#define SD_CMD_SET_BLOCKLEN 16 ++#define SD_CMD_READ_SINGLE_BLOCK 17 ++#define SD_CMD_READ_MULTIPLE_BLOCK 18 ++#define SD_CMD_WRITE_BLOCK 24 ++#define SD_CMD_WRITE_MULTIPLE_BLOCK 25 ++#define SD_CMD_PROGRAM_CSD 27 ++#define SD_CMD_SET_WRITE_PROT 28 ++#define SD_CMD_CLR_WRITE_PROT 29 ++#define SD_CMD_SEND_WRITE_PROT 30 ++#define SD_CMD_ERASE_WR_BLK_START 32 ++#define SD_CMD_ERASE_WR_BLK_END 33 ++#define SD_CMD_ERASE 38 ++#define SD_CMD_LOCK_UNLOCK 42 ++#define SD_CMD_IO_RW_DIRECT 52 /* mandatory for SDIO */ ++#define SD_CMD_IO_RW_EXTENDED 53 /* mandatory for SDIO */ ++#define SD_CMD_APP_CMD 55 ++#define SD_CMD_GEN_CMD 56 ++#define SD_CMD_READ_OCR 58 ++#define SD_CMD_CRC_ON_OFF 59 /* mandatory for SDIO */ ++#define SD_ACMD_SD_STATUS 13 ++#define SD_ACMD_SEND_NUM_WR_BLOCKS 22 ++#define SD_ACMD_SET_WR_BLOCK_ERASE_CNT 23 ++#define SD_ACMD_SD_SEND_OP_COND 41 ++#define SD_ACMD_SET_CLR_CARD_DETECT 42 ++#define SD_ACMD_SEND_SCR 51 ++ ++/* argument for SD_CMD_IO_RW_DIRECT and SD_CMD_IO_RW_EXTENDED */ ++#define SD_IO_OP_READ 0 /* Read_Write: Read */ ++#define SD_IO_OP_WRITE 1 /* Read_Write: Write */ ++#define SD_IO_RW_NORMAL 0 /* no RAW */ ++#define SD_IO_RW_RAW 1 /* RAW */ ++#define SD_IO_BYTE_MODE 0 /* Byte Mode */ ++#define SD_IO_BLOCK_MODE 1 /* BlockMode */ ++#define SD_IO_FIXED_ADDRESS 0 /* fix Address */ ++#define SD_IO_INCREMENT_ADDRESS 1 /* IncrementAddress */ ++ ++/* build SD_CMD_IO_RW_DIRECT Argument */ ++#define SDIO_IO_RW_DIRECT_ARG(rw, raw, func, addr, data) \ ++ ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((raw) & 1) << 27) | \ ++ (((addr) & 0x1FFFF) << 9) | ((data) & 0xFF)) ++ ++/* build SD_CMD_IO_RW_EXTENDED Argument */ ++#define SDIO_IO_RW_EXTENDED_ARG(rw, blk, func, addr, inc_addr, count) \ ++ ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((blk) & 1) << 27) | \ ++ (((inc_addr) & 1) << 26) | (((addr) & 0x1FFFF) << 9) | ((count) & 0x1FF)) ++ ++/* SDIO response parameters */ ++#define SD_RSP_NO_NONE 0 ++#define SD_RSP_NO_1 1 ++#define SD_RSP_NO_2 2 ++#define SD_RSP_NO_3 3 ++#define SD_RSP_NO_4 4 ++#define SD_RSP_NO_5 5 ++#define SD_RSP_NO_6 6 ++ ++ /* Modified R6 response (to CMD3) */ ++#define SD_RSP_MR6_COM_CRC_ERROR 0x8000 ++#define SD_RSP_MR6_ILLEGAL_COMMAND 0x4000 ++#define SD_RSP_MR6_ERROR 0x2000 ++ ++ /* Modified R1 in R4 Response (to CMD5) */ ++#define SD_RSP_MR1_SBIT 0x80 ++#define SD_RSP_MR1_PARAMETER_ERROR 0x40 ++#define SD_RSP_MR1_RFU5 0x20 ++#define SD_RSP_MR1_FUNC_NUM_ERROR 0x10 ++#define SD_RSP_MR1_COM_CRC_ERROR 0x08 ++#define SD_RSP_MR1_ILLEGAL_COMMAND 0x04 ++#define SD_RSP_MR1_RFU1 0x02 ++#define SD_RSP_MR1_IDLE_STATE 0x01 ++ ++ /* R5 response (to CMD52 and CMD53) */ ++#define SD_RSP_R5_COM_CRC_ERROR 0x80 ++#define SD_RSP_R5_ILLEGAL_COMMAND 0x40 ++#define SD_RSP_R5_IO_CURRENTSTATE1 0x20 ++#define SD_RSP_R5_IO_CURRENTSTATE0 0x10 ++#define SD_RSP_R5_ERROR 0x08 ++#define SD_RSP_R5_RFU 0x04 ++#define SD_RSP_R5_FUNC_NUM_ERROR 0x02 ++#define SD_RSP_R5_OUT_OF_RANGE 0x01 ++ ++#define SD_RSP_R5_ERRBITS 0xCB ++ ++ ++/* ------------------------------------------------ ++ * SDIO Commands and responses ++ * ++ * I/O only commands are: ++ * CMD0, CMD3, CMD5, CMD7, CMD14, CMD15, CMD52, CMD53 ++ * ------------------------------------------------ ++ */ ++ ++/* SDIO Commands */ ++#define SDIOH_CMD_0 0 ++#define SDIOH_CMD_3 3 ++#define SDIOH_CMD_5 5 ++#define SDIOH_CMD_7 7 ++#define SDIOH_CMD_11 11 ++#define SDIOH_CMD_14 14 ++#define SDIOH_CMD_15 15 ++#define SDIOH_CMD_19 19 ++#define SDIOH_CMD_52 52 ++#define SDIOH_CMD_53 53 ++#define SDIOH_CMD_59 59 ++ ++/* SDIO Command Responses */ ++#define SDIOH_RSP_NONE 0 ++#define SDIOH_RSP_R1 1 ++#define SDIOH_RSP_R2 2 ++#define SDIOH_RSP_R3 3 ++#define SDIOH_RSP_R4 4 ++#define SDIOH_RSP_R5 5 ++#define SDIOH_RSP_R6 6 ++ ++/* ++ * SDIO Response Error flags ++ */ ++#define SDIOH_RSP5_ERROR_FLAGS 0xCB ++ ++/* ------------------------------------------------ ++ * SDIO Command structures. I/O only commands are: ++ * ++ * CMD0, CMD3, CMD5, CMD7, CMD15, CMD52, CMD53 ++ * ------------------------------------------------ ++ */ ++ ++#define CMD5_OCR_M BITFIELD_MASK(24) ++#define CMD5_OCR_S 0 ++ ++#define CMD5_S18R_M BITFIELD_MASK(1) ++#define CMD5_S18R_S 24 ++ ++#define CMD7_RCA_M BITFIELD_MASK(16) ++#define CMD7_RCA_S 16 ++ ++#define CMD14_RCA_M BITFIELD_MASK(16) ++#define CMD14_RCA_S 16 ++#define CMD14_SLEEP_M BITFIELD_MASK(1) ++#define CMD14_SLEEP_S 15 ++ ++#define CMD_15_RCA_M BITFIELD_MASK(16) ++#define CMD_15_RCA_S 16 ++ ++#define CMD52_DATA_M BITFIELD_MASK(8) /* Bits [7:0] - Write Data/Stuff bits of CMD52 ++ */ ++#define CMD52_DATA_S 0 ++#define CMD52_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */ ++#define CMD52_REG_ADDR_S 9 ++#define CMD52_RAW_M BITFIELD_MASK(1) /* Bit 27 - Read after Write flag */ ++#define CMD52_RAW_S 27 ++#define CMD52_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */ ++#define CMD52_FUNCTION_S 28 ++#define CMD52_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */ ++#define CMD52_RW_FLAG_S 31 ++ ++ ++#define CMD53_BYTE_BLK_CNT_M BITFIELD_MASK(9) /* Bits [8:0] - Byte/Block Count of CMD53 */ ++#define CMD53_BYTE_BLK_CNT_S 0 ++#define CMD53_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */ ++#define CMD53_REG_ADDR_S 9 ++#define CMD53_OP_CODE_M BITFIELD_MASK(1) /* Bit 26 - R/W Operation Code */ ++#define CMD53_OP_CODE_S 26 ++#define CMD53_BLK_MODE_M BITFIELD_MASK(1) /* Bit 27 - Block Mode */ ++#define CMD53_BLK_MODE_S 27 ++#define CMD53_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */ ++#define CMD53_FUNCTION_S 28 ++#define CMD53_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */ ++#define CMD53_RW_FLAG_S 31 ++ ++/* ------------------------------------------------------ ++ * SDIO Command Response structures for SD1 and SD4 modes ++ * ----------------------------------------------------- ++ */ ++#define RSP4_IO_OCR_M BITFIELD_MASK(24) /* Bits [23:0] - Card's OCR Bits [23:0] */ ++#define RSP4_IO_OCR_S 0 ++ ++#define RSP4_S18A_M BITFIELD_MASK(1) /* Bits [23:0] - Card's OCR Bits [23:0] */ ++#define RSP4_S18A_S 24 ++ ++#define RSP4_STUFF_M BITFIELD_MASK(3) /* Bits [26:24] - Stuff bits */ ++#define RSP4_STUFF_S 24 ++#define RSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 27 - Memory present */ ++#define RSP4_MEM_PRESENT_S 27 ++#define RSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [30:28] - Number of I/O funcs */ ++#define RSP4_NUM_FUNCS_S 28 ++#define RSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 31 - SDIO card ready */ ++#define RSP4_CARD_READY_S 31 ++ ++#define RSP6_STATUS_M BITFIELD_MASK(16) /* Bits [15:0] - Card status bits [19,22,23,12:0] ++ */ ++#define RSP6_STATUS_S 0 ++#define RSP6_IO_RCA_M BITFIELD_MASK(16) /* Bits [31:16] - RCA bits[31-16] */ ++#define RSP6_IO_RCA_S 16 ++ ++#define RSP1_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error */ ++#define RSP1_AKE_SEQ_ERROR_S 3 ++#define RSP1_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */ ++#define RSP1_APP_CMD_S 5 ++#define RSP1_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data (buff empty) */ ++#define RSP1_READY_FOR_DATA_S 8 ++#define RSP1_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - State of card ++ * when Cmd was received ++ */ ++#define RSP1_CURR_STATE_S 9 ++#define RSP1_EARSE_RESET_M BITFIELD_MASK(1) /* Bit 13 - Erase seq cleared */ ++#define RSP1_EARSE_RESET_S 13 ++#define RSP1_CARD_ECC_DISABLE_M BITFIELD_MASK(1) /* Bit 14 - Card ECC disabled */ ++#define RSP1_CARD_ECC_DISABLE_S 14 ++#define RSP1_WP_ERASE_SKIP_M BITFIELD_MASK(1) /* Bit 15 - Partial blocks erased due to W/P */ ++#define RSP1_WP_ERASE_SKIP_S 15 ++#define RSP1_CID_CSD_OVERW_M BITFIELD_MASK(1) /* Bit 16 - Illegal write to CID or R/O bits ++ * of CSD ++ */ ++#define RSP1_CID_CSD_OVERW_S 16 ++#define RSP1_ERROR_M BITFIELD_MASK(1) /* Bit 19 - General/Unknown error */ ++#define RSP1_ERROR_S 19 ++#define RSP1_CC_ERROR_M BITFIELD_MASK(1) /* Bit 20 - Internal Card Control error */ ++#define RSP1_CC_ERROR_S 20 ++#define RSP1_CARD_ECC_FAILED_M BITFIELD_MASK(1) /* Bit 21 - Card internal ECC failed ++ * to correct data ++ */ ++#define RSP1_CARD_ECC_FAILED_S 21 ++#define RSP1_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 22 - Cmd not legal for the card state */ ++#define RSP1_ILLEGAL_CMD_S 22 ++#define RSP1_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 23 - CRC check of previous command failed ++ */ ++#define RSP1_COM_CRC_ERROR_S 23 ++#define RSP1_LOCK_UNLOCK_FAIL_M BITFIELD_MASK(1) /* Bit 24 - Card lock-unlock Cmd Seq error */ ++#define RSP1_LOCK_UNLOCK_FAIL_S 24 ++#define RSP1_CARD_LOCKED_M BITFIELD_MASK(1) /* Bit 25 - Card locked by the host */ ++#define RSP1_CARD_LOCKED_S 25 ++#define RSP1_WP_VIOLATION_M BITFIELD_MASK(1) /* Bit 26 - Attempt to program ++ * write-protected blocks ++ */ ++#define RSP1_WP_VIOLATION_S 26 ++#define RSP1_ERASE_PARAM_M BITFIELD_MASK(1) /* Bit 27 - Invalid erase blocks */ ++#define RSP1_ERASE_PARAM_S 27 ++#define RSP1_ERASE_SEQ_ERR_M BITFIELD_MASK(1) /* Bit 28 - Erase Cmd seq error */ ++#define RSP1_ERASE_SEQ_ERR_S 28 ++#define RSP1_BLK_LEN_ERR_M BITFIELD_MASK(1) /* Bit 29 - Block length error */ ++#define RSP1_BLK_LEN_ERR_S 29 ++#define RSP1_ADDR_ERR_M BITFIELD_MASK(1) /* Bit 30 - Misaligned address */ ++#define RSP1_ADDR_ERR_S 30 ++#define RSP1_OUT_OF_RANGE_M BITFIELD_MASK(1) /* Bit 31 - Cmd arg was out of range */ ++#define RSP1_OUT_OF_RANGE_S 31 ++ ++ ++#define RSP5_DATA_M BITFIELD_MASK(8) /* Bits [0:7] - data */ ++#define RSP5_DATA_S 0 ++#define RSP5_FLAGS_M BITFIELD_MASK(8) /* Bit [15:8] - Rsp flags */ ++#define RSP5_FLAGS_S 8 ++#define RSP5_STUFF_M BITFIELD_MASK(16) /* Bits [31:16] - Stuff bits */ ++#define RSP5_STUFF_S 16 ++ ++/* ---------------------------------------------- ++ * SDIO Command Response structures for SPI mode ++ * ---------------------------------------------- ++ */ ++#define SPIRSP4_IO_OCR_M BITFIELD_MASK(16) /* Bits [15:0] - Card's OCR Bits [23:8] */ ++#define SPIRSP4_IO_OCR_S 0 ++#define SPIRSP4_STUFF_M BITFIELD_MASK(3) /* Bits [18:16] - Stuff bits */ ++#define SPIRSP4_STUFF_S 16 ++#define SPIRSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 19 - Memory present */ ++#define SPIRSP4_MEM_PRESENT_S 19 ++#define SPIRSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [22:20] - Number of I/O funcs */ ++#define SPIRSP4_NUM_FUNCS_S 20 ++#define SPIRSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 23 - SDIO card ready */ ++#define SPIRSP4_CARD_READY_S 23 ++#define SPIRSP4_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - idle state */ ++#define SPIRSP4_IDLE_STATE_S 24 ++#define SPIRSP4_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */ ++#define SPIRSP4_ILLEGAL_CMD_S 26 ++#define SPIRSP4_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */ ++#define SPIRSP4_COM_CRC_ERROR_S 27 ++#define SPIRSP4_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error ++ */ ++#define SPIRSP4_FUNC_NUM_ERROR_S 28 ++#define SPIRSP4_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */ ++#define SPIRSP4_PARAM_ERROR_S 30 ++#define SPIRSP4_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */ ++#define SPIRSP4_START_BIT_S 31 ++ ++#define SPIRSP5_DATA_M BITFIELD_MASK(8) /* Bits [23:16] - R/W Data */ ++#define SPIRSP5_DATA_S 16 ++#define SPIRSP5_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - Idle state */ ++#define SPIRSP5_IDLE_STATE_S 24 ++#define SPIRSP5_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */ ++#define SPIRSP5_ILLEGAL_CMD_S 26 ++#define SPIRSP5_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */ ++#define SPIRSP5_COM_CRC_ERROR_S 27 ++#define SPIRSP5_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error ++ */ ++#define SPIRSP5_FUNC_NUM_ERROR_S 28 ++#define SPIRSP5_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */ ++#define SPIRSP5_PARAM_ERROR_S 30 ++#define SPIRSP5_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */ ++#define SPIRSP5_START_BIT_S 31 ++ ++/* RSP6 card status format; Pg 68 Physical Layer spec v 1.10 */ ++#define RSP6STAT_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error ++ */ ++#define RSP6STAT_AKE_SEQ_ERROR_S 3 ++#define RSP6STAT_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */ ++#define RSP6STAT_APP_CMD_S 5 ++#define RSP6STAT_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data ++ * (buff empty) ++ */ ++#define RSP6STAT_READY_FOR_DATA_S 8 ++#define RSP6STAT_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - Card state at ++ * Cmd reception ++ */ ++#define RSP6STAT_CURR_STATE_S 9 ++#define RSP6STAT_ERROR_M BITFIELD_MASK(1) /* Bit 13 - General/Unknown error Bit 19 ++ */ ++#define RSP6STAT_ERROR_S 13 ++#define RSP6STAT_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 14 - Illegal cmd for ++ * card state Bit 22 ++ */ ++#define RSP6STAT_ILLEGAL_CMD_S 14 ++#define RSP6STAT_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 15 - CRC previous command ++ * failed Bit 23 ++ */ ++#define RSP6STAT_COM_CRC_ERROR_S 15 ++ ++#define SDIOH_XFER_TYPE_READ SD_IO_OP_READ ++#define SDIOH_XFER_TYPE_WRITE SD_IO_OP_WRITE ++ ++/* command issue options */ ++#define CMD_OPTION_DEFAULT 0 ++#define CMD_OPTION_TUNING 1 ++#endif /* _SDIO_H */ +diff --git a/drivers/net/wireless/ap6211/include/sdioh.h b/drivers/net/wireless/ap6211/include/sdioh.h +new file mode 100755 +index 0000000..5517a71 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sdioh.h +@@ -0,0 +1,445 @@ ++/* ++ * SDIO Host Controller Spec header file ++ * Register map and definitions for the Standard Host Controller ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sdioh.h 347633 2012-07-27 11:02:02Z $ ++ */ ++ ++#ifndef _SDIOH_H ++#define _SDIOH_H ++ ++#define SD_SysAddr 0x000 ++#define SD_BlockSize 0x004 ++#define SD_BlockCount 0x006 ++#define SD_Arg0 0x008 ++#define SD_Arg1 0x00A ++#define SD_TransferMode 0x00C ++#define SD_Command 0x00E ++#define SD_Response0 0x010 ++#define SD_Response1 0x012 ++#define SD_Response2 0x014 ++#define SD_Response3 0x016 ++#define SD_Response4 0x018 ++#define SD_Response5 0x01A ++#define SD_Response6 0x01C ++#define SD_Response7 0x01E ++#define SD_BufferDataPort0 0x020 ++#define SD_BufferDataPort1 0x022 ++#define SD_PresentState 0x024 ++#define SD_HostCntrl 0x028 ++#define SD_PwrCntrl 0x029 ++#define SD_BlockGapCntrl 0x02A ++#define SD_WakeupCntrl 0x02B ++#define SD_ClockCntrl 0x02C ++#define SD_TimeoutCntrl 0x02E ++#define SD_SoftwareReset 0x02F ++#define SD_IntrStatus 0x030 ++#define SD_ErrorIntrStatus 0x032 ++#define SD_IntrStatusEnable 0x034 ++#define SD_ErrorIntrStatusEnable 0x036 ++#define SD_IntrSignalEnable 0x038 ++#define SD_ErrorIntrSignalEnable 0x03A ++#define SD_CMD12ErrorStatus 0x03C ++#define SD_Capabilities 0x040 ++#define SD_Capabilities3 0x044 ++#define SD_MaxCurCap 0x048 ++#define SD_MaxCurCap_Reserved 0x04C ++#define SD_ADMA_ErrStatus 0x054 ++#define SD_ADMA_SysAddr 0x58 ++#define SD_SlotInterruptStatus 0x0FC ++#define SD_HostControllerVersion 0x0FE ++#define SD_GPIO_Reg 0x100 ++#define SD_GPIO_OE 0x104 ++#define SD_GPIO_Enable 0x108 ++ ++/* SD specific registers in PCI config space */ ++#define SD_SlotInfo 0x40 ++ ++/* HC 3.0 specific registers and offsets */ ++#define SD3_HostCntrl2 0x03E ++/* preset regsstart and count */ ++#define SD3_PresetValStart 0x060 ++#define SD3_PresetValCount 8 ++/* preset-indiv regs */ ++#define SD3_PresetVal_init 0x060 ++#define SD3_PresetVal_default 0x062 ++#define SD3_PresetVal_HS 0x064 ++#define SD3_PresetVal_SDR12 0x066 ++#define SD3_PresetVal_SDR25 0x068 ++#define SD3_PresetVal_SDR50 0x06a ++#define SD3_PresetVal_SDR104 0x06c ++#define SD3_PresetVal_DDR50 0x06e ++/* SDIO3.0 Revx specific Registers */ ++#define SD3_Tuning_Info_Register 0x0EC ++#define SD3_WL_BT_reset_register 0x0F0 ++ ++ ++/* preset value indices */ ++#define SD3_PRESETVAL_INITIAL_IX 0 ++#define SD3_PRESETVAL_DESPEED_IX 1 ++#define SD3_PRESETVAL_HISPEED_IX 2 ++#define SD3_PRESETVAL_SDR12_IX 3 ++#define SD3_PRESETVAL_SDR25_IX 4 ++#define SD3_PRESETVAL_SDR50_IX 5 ++#define SD3_PRESETVAL_SDR104_IX 6 ++#define SD3_PRESETVAL_DDR50_IX 7 ++ ++/* SD_Capabilities reg (0x040) */ ++#define CAP_TO_CLKFREQ_M BITFIELD_MASK(6) ++#define CAP_TO_CLKFREQ_S 0 ++#define CAP_TO_CLKUNIT_M BITFIELD_MASK(1) ++#define CAP_TO_CLKUNIT_S 7 ++/* Note: for sdio-2.0 case, this mask has to be 6 bits, but msb 2 ++ bits are reserved. going ahead with 8 bits, as it is req for 3.0 ++*/ ++#define CAP_BASECLK_M BITFIELD_MASK(8) ++#define CAP_BASECLK_S 8 ++#define CAP_MAXBLOCK_M BITFIELD_MASK(2) ++#define CAP_MAXBLOCK_S 16 ++#define CAP_ADMA2_M BITFIELD_MASK(1) ++#define CAP_ADMA2_S 19 ++#define CAP_ADMA1_M BITFIELD_MASK(1) ++#define CAP_ADMA1_S 20 ++#define CAP_HIGHSPEED_M BITFIELD_MASK(1) ++#define CAP_HIGHSPEED_S 21 ++#define CAP_DMA_M BITFIELD_MASK(1) ++#define CAP_DMA_S 22 ++#define CAP_SUSPEND_M BITFIELD_MASK(1) ++#define CAP_SUSPEND_S 23 ++#define CAP_VOLT_3_3_M BITFIELD_MASK(1) ++#define CAP_VOLT_3_3_S 24 ++#define CAP_VOLT_3_0_M BITFIELD_MASK(1) ++#define CAP_VOLT_3_0_S 25 ++#define CAP_VOLT_1_8_M BITFIELD_MASK(1) ++#define CAP_VOLT_1_8_S 26 ++#define CAP_64BIT_HOST_M BITFIELD_MASK(1) ++#define CAP_64BIT_HOST_S 28 ++ ++#define SDIO_OCR_READ_FAIL (2) ++ ++ ++#define CAP_ASYNCINT_SUP_M BITFIELD_MASK(1) ++#define CAP_ASYNCINT_SUP_S 29 ++ ++#define CAP_SLOTTYPE_M BITFIELD_MASK(2) ++#define CAP_SLOTTYPE_S 30 ++ ++#define CAP3_MSBits_OFFSET (32) ++/* note: following are caps MSB32 bits. ++ So the bits start from 0, instead of 32. that is why ++ CAP3_MSBits_OFFSET is subtracted. ++*/ ++#define CAP3_SDR50_SUP_M BITFIELD_MASK(1) ++#define CAP3_SDR50_SUP_S (32 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_SDR104_SUP_M BITFIELD_MASK(1) ++#define CAP3_SDR104_SUP_S (33 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_DDR50_SUP_M BITFIELD_MASK(1) ++#define CAP3_DDR50_SUP_S (34 - CAP3_MSBits_OFFSET) ++ ++/* for knowing the clk caps in a single read */ ++#define CAP3_30CLKCAP_M BITFIELD_MASK(3) ++#define CAP3_30CLKCAP_S (32 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_DRIVTYPE_A_M BITFIELD_MASK(1) ++#define CAP3_DRIVTYPE_A_S (36 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_DRIVTYPE_C_M BITFIELD_MASK(1) ++#define CAP3_DRIVTYPE_C_S (37 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_DRIVTYPE_D_M BITFIELD_MASK(1) ++#define CAP3_DRIVTYPE_D_S (38 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_RETUNING_TC_M BITFIELD_MASK(4) ++#define CAP3_RETUNING_TC_S (40 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_TUNING_SDR50_M BITFIELD_MASK(1) ++#define CAP3_TUNING_SDR50_S (45 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_RETUNING_MODES_M BITFIELD_MASK(2) ++#define CAP3_RETUNING_MODES_S (46 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_CLK_MULT_M BITFIELD_MASK(8) ++#define CAP3_CLK_MULT_S (48 - CAP3_MSBits_OFFSET) ++ ++#define PRESET_DRIVR_SELECT_M BITFIELD_MASK(2) ++#define PRESET_DRIVR_SELECT_S 14 ++ ++#define PRESET_CLK_DIV_M BITFIELD_MASK(10) ++#define PRESET_CLK_DIV_S 0 ++ ++/* SD_MaxCurCap reg (0x048) */ ++#define CAP_CURR_3_3_M BITFIELD_MASK(8) ++#define CAP_CURR_3_3_S 0 ++#define CAP_CURR_3_0_M BITFIELD_MASK(8) ++#define CAP_CURR_3_0_S 8 ++#define CAP_CURR_1_8_M BITFIELD_MASK(8) ++#define CAP_CURR_1_8_S 16 ++ ++/* SD_SysAddr: Offset 0x0000, Size 4 bytes */ ++ ++/* SD_BlockSize: Offset 0x004, Size 2 bytes */ ++#define BLKSZ_BLKSZ_M BITFIELD_MASK(12) ++#define BLKSZ_BLKSZ_S 0 ++#define BLKSZ_BNDRY_M BITFIELD_MASK(3) ++#define BLKSZ_BNDRY_S 12 ++ ++/* SD_BlockCount: Offset 0x006, size 2 bytes */ ++ ++/* SD_Arg0: Offset 0x008, size = 4 bytes */ ++/* SD_TransferMode Offset 0x00C, size = 2 bytes */ ++#define XFER_DMA_ENABLE_M BITFIELD_MASK(1) ++#define XFER_DMA_ENABLE_S 0 ++#define XFER_BLK_COUNT_EN_M BITFIELD_MASK(1) ++#define XFER_BLK_COUNT_EN_S 1 ++#define XFER_CMD_12_EN_M BITFIELD_MASK(1) ++#define XFER_CMD_12_EN_S 2 ++#define XFER_DATA_DIRECTION_M BITFIELD_MASK(1) ++#define XFER_DATA_DIRECTION_S 4 ++#define XFER_MULTI_BLOCK_M BITFIELD_MASK(1) ++#define XFER_MULTI_BLOCK_S 5 ++ ++/* SD_Command: Offset 0x00E, size = 2 bytes */ ++/* resp_type field */ ++#define RESP_TYPE_NONE 0 ++#define RESP_TYPE_136 1 ++#define RESP_TYPE_48 2 ++#define RESP_TYPE_48_BUSY 3 ++/* type field */ ++#define CMD_TYPE_NORMAL 0 ++#define CMD_TYPE_SUSPEND 1 ++#define CMD_TYPE_RESUME 2 ++#define CMD_TYPE_ABORT 3 ++ ++#define CMD_RESP_TYPE_M BITFIELD_MASK(2) /* Bits [0-1] - Response type */ ++#define CMD_RESP_TYPE_S 0 ++#define CMD_CRC_EN_M BITFIELD_MASK(1) /* Bit 3 - CRC enable */ ++#define CMD_CRC_EN_S 3 ++#define CMD_INDEX_EN_M BITFIELD_MASK(1) /* Bit 4 - Enable index checking */ ++#define CMD_INDEX_EN_S 4 ++#define CMD_DATA_EN_M BITFIELD_MASK(1) /* Bit 5 - Using DAT line */ ++#define CMD_DATA_EN_S 5 ++#define CMD_TYPE_M BITFIELD_MASK(2) /* Bit [6-7] - Normal, abort, resume, etc ++ */ ++#define CMD_TYPE_S 6 ++#define CMD_INDEX_M BITFIELD_MASK(6) /* Bits [8-13] - Command number */ ++#define CMD_INDEX_S 8 ++ ++/* SD_BufferDataPort0 : Offset 0x020, size = 2 or 4 bytes */ ++/* SD_BufferDataPort1 : Offset 0x022, size = 2 bytes */ ++/* SD_PresentState : Offset 0x024, size = 4 bytes */ ++#define PRES_CMD_INHIBIT_M BITFIELD_MASK(1) /* Bit 0 May use CMD */ ++#define PRES_CMD_INHIBIT_S 0 ++#define PRES_DAT_INHIBIT_M BITFIELD_MASK(1) /* Bit 1 May use DAT */ ++#define PRES_DAT_INHIBIT_S 1 ++#define PRES_DAT_BUSY_M BITFIELD_MASK(1) /* Bit 2 DAT is busy */ ++#define PRES_DAT_BUSY_S 2 ++#define PRES_PRESENT_RSVD_M BITFIELD_MASK(5) /* Bit [3-7] rsvd */ ++#define PRES_PRESENT_RSVD_S 3 ++#define PRES_WRITE_ACTIVE_M BITFIELD_MASK(1) /* Bit 8 Write is active */ ++#define PRES_WRITE_ACTIVE_S 8 ++#define PRES_READ_ACTIVE_M BITFIELD_MASK(1) /* Bit 9 Read is active */ ++#define PRES_READ_ACTIVE_S 9 ++#define PRES_WRITE_DATA_RDY_M BITFIELD_MASK(1) /* Bit 10 Write buf is avail */ ++#define PRES_WRITE_DATA_RDY_S 10 ++#define PRES_READ_DATA_RDY_M BITFIELD_MASK(1) /* Bit 11 Read buf data avail */ ++#define PRES_READ_DATA_RDY_S 11 ++#define PRES_CARD_PRESENT_M BITFIELD_MASK(1) /* Bit 16 Card present - debounced */ ++#define PRES_CARD_PRESENT_S 16 ++#define PRES_CARD_STABLE_M BITFIELD_MASK(1) /* Bit 17 Debugging */ ++#define PRES_CARD_STABLE_S 17 ++#define PRES_CARD_PRESENT_RAW_M BITFIELD_MASK(1) /* Bit 18 Not debounced */ ++#define PRES_CARD_PRESENT_RAW_S 18 ++#define PRES_WRITE_ENABLED_M BITFIELD_MASK(1) /* Bit 19 Write protected? */ ++#define PRES_WRITE_ENABLED_S 19 ++#define PRES_DAT_SIGNAL_M BITFIELD_MASK(4) /* Bit [20-23] Debugging */ ++#define PRES_DAT_SIGNAL_S 20 ++#define PRES_CMD_SIGNAL_M BITFIELD_MASK(1) /* Bit 24 Debugging */ ++#define PRES_CMD_SIGNAL_S 24 ++ ++/* SD_HostCntrl: Offset 0x028, size = 1 bytes */ ++#define HOST_LED_M BITFIELD_MASK(1) /* Bit 0 LED On/Off */ ++#define HOST_LED_S 0 ++#define HOST_DATA_WIDTH_M BITFIELD_MASK(1) /* Bit 1 4 bit enable */ ++#define HOST_DATA_WIDTH_S 1 ++#define HOST_HI_SPEED_EN_M BITFIELD_MASK(1) /* Bit 2 High speed vs low speed */ ++#define HOST_DMA_SEL_S 3 ++#define HOST_DMA_SEL_M BITFIELD_MASK(2) /* Bit 4:3 DMA Select */ ++#define HOST_HI_SPEED_EN_S 2 ++ ++/* Host Control2: */ ++#define HOSTCtrl2_PRESVAL_EN_M BITFIELD_MASK(1) /* 1 bit */ ++#define HOSTCtrl2_PRESVAL_EN_S 15 /* bit# */ ++ ++#define HOSTCtrl2_ASYINT_EN_M BITFIELD_MASK(1) /* 1 bit */ ++#define HOSTCtrl2_ASYINT_EN_S 14 /* bit# */ ++ ++#define HOSTCtrl2_SAMPCLK_SEL_M BITFIELD_MASK(1) /* 1 bit */ ++#define HOSTCtrl2_SAMPCLK_SEL_S 7 /* bit# */ ++ ++#define HOSTCtrl2_EXEC_TUNING_M BITFIELD_MASK(1) /* 1 bit */ ++#define HOSTCtrl2_EXEC_TUNING_S 6 /* bit# */ ++ ++#define HOSTCtrl2_DRIVSTRENGTH_SEL_M BITFIELD_MASK(2) /* 2 bit */ ++#define HOSTCtrl2_DRIVSTRENGTH_SEL_S 4 /* bit# */ ++ ++#define HOSTCtrl2_1_8SIG_EN_M BITFIELD_MASK(1) /* 1 bit */ ++#define HOSTCtrl2_1_8SIG_EN_S 3 /* bit# */ ++ ++#define HOSTCtrl2_UHSMODE_SEL_M BITFIELD_MASK(3) /* 3 bit */ ++#define HOSTCtrl2_UHSMODE_SEL_S 0 /* bit# */ ++ ++#define HOST_CONTR_VER_2 (1) ++#define HOST_CONTR_VER_3 (2) ++ ++/* misc defines */ ++#define SD1_MODE 0x1 /* SD Host Cntrlr Spec */ ++#define SD4_MODE 0x2 /* SD Host Cntrlr Spec */ ++ ++/* SD_PwrCntrl: Offset 0x029, size = 1 bytes */ ++#define PWR_BUS_EN_M BITFIELD_MASK(1) /* Bit 0 Power the bus */ ++#define PWR_BUS_EN_S 0 ++#define PWR_VOLTS_M BITFIELD_MASK(3) /* Bit [1-3] Voltage Select */ ++#define PWR_VOLTS_S 1 ++ ++/* SD_SoftwareReset: Offset 0x02F, size = 1 byte */ ++#define SW_RESET_ALL_M BITFIELD_MASK(1) /* Bit 0 Reset All */ ++#define SW_RESET_ALL_S 0 ++#define SW_RESET_CMD_M BITFIELD_MASK(1) /* Bit 1 CMD Line Reset */ ++#define SW_RESET_CMD_S 1 ++#define SW_RESET_DAT_M BITFIELD_MASK(1) /* Bit 2 DAT Line Reset */ ++#define SW_RESET_DAT_S 2 ++ ++/* SD_IntrStatus: Offset 0x030, size = 2 bytes */ ++/* Defs also serve SD_IntrStatusEnable and SD_IntrSignalEnable */ ++#define INTSTAT_CMD_COMPLETE_M BITFIELD_MASK(1) /* Bit 0 */ ++#define INTSTAT_CMD_COMPLETE_S 0 ++#define INTSTAT_XFER_COMPLETE_M BITFIELD_MASK(1) ++#define INTSTAT_XFER_COMPLETE_S 1 ++#define INTSTAT_BLOCK_GAP_EVENT_M BITFIELD_MASK(1) ++#define INTSTAT_BLOCK_GAP_EVENT_S 2 ++#define INTSTAT_DMA_INT_M BITFIELD_MASK(1) ++#define INTSTAT_DMA_INT_S 3 ++#define INTSTAT_BUF_WRITE_READY_M BITFIELD_MASK(1) ++#define INTSTAT_BUF_WRITE_READY_S 4 ++#define INTSTAT_BUF_READ_READY_M BITFIELD_MASK(1) ++#define INTSTAT_BUF_READ_READY_S 5 ++#define INTSTAT_CARD_INSERTION_M BITFIELD_MASK(1) ++#define INTSTAT_CARD_INSERTION_S 6 ++#define INTSTAT_CARD_REMOVAL_M BITFIELD_MASK(1) ++#define INTSTAT_CARD_REMOVAL_S 7 ++#define INTSTAT_CARD_INT_M BITFIELD_MASK(1) ++#define INTSTAT_CARD_INT_S 8 ++#define INTSTAT_RETUNING_INT_M BITFIELD_MASK(1) /* Bit 12 */ ++#define INTSTAT_RETUNING_INT_S 12 ++#define INTSTAT_ERROR_INT_M BITFIELD_MASK(1) /* Bit 15 */ ++#define INTSTAT_ERROR_INT_S 15 ++ ++/* SD_ErrorIntrStatus: Offset 0x032, size = 2 bytes */ ++/* Defs also serve SD_ErrorIntrStatusEnable and SD_ErrorIntrSignalEnable */ ++#define ERRINT_CMD_TIMEOUT_M BITFIELD_MASK(1) ++#define ERRINT_CMD_TIMEOUT_S 0 ++#define ERRINT_CMD_CRC_M BITFIELD_MASK(1) ++#define ERRINT_CMD_CRC_S 1 ++#define ERRINT_CMD_ENDBIT_M BITFIELD_MASK(1) ++#define ERRINT_CMD_ENDBIT_S 2 ++#define ERRINT_CMD_INDEX_M BITFIELD_MASK(1) ++#define ERRINT_CMD_INDEX_S 3 ++#define ERRINT_DATA_TIMEOUT_M BITFIELD_MASK(1) ++#define ERRINT_DATA_TIMEOUT_S 4 ++#define ERRINT_DATA_CRC_M BITFIELD_MASK(1) ++#define ERRINT_DATA_CRC_S 5 ++#define ERRINT_DATA_ENDBIT_M BITFIELD_MASK(1) ++#define ERRINT_DATA_ENDBIT_S 6 ++#define ERRINT_CURRENT_LIMIT_M BITFIELD_MASK(1) ++#define ERRINT_CURRENT_LIMIT_S 7 ++#define ERRINT_AUTO_CMD12_M BITFIELD_MASK(1) ++#define ERRINT_AUTO_CMD12_S 8 ++#define ERRINT_VENDOR_M BITFIELD_MASK(4) ++#define ERRINT_VENDOR_S 12 ++#define ERRINT_ADMA_M BITFIELD_MASK(1) ++#define ERRINT_ADMA_S 9 ++ ++/* Also provide definitions in "normal" form to allow combined masks */ ++#define ERRINT_CMD_TIMEOUT_BIT 0x0001 ++#define ERRINT_CMD_CRC_BIT 0x0002 ++#define ERRINT_CMD_ENDBIT_BIT 0x0004 ++#define ERRINT_CMD_INDEX_BIT 0x0008 ++#define ERRINT_DATA_TIMEOUT_BIT 0x0010 ++#define ERRINT_DATA_CRC_BIT 0x0020 ++#define ERRINT_DATA_ENDBIT_BIT 0x0040 ++#define ERRINT_CURRENT_LIMIT_BIT 0x0080 ++#define ERRINT_AUTO_CMD12_BIT 0x0100 ++#define ERRINT_ADMA_BIT 0x0200 ++ ++/* Masks to select CMD vs. DATA errors */ ++#define ERRINT_CMD_ERRS (ERRINT_CMD_TIMEOUT_BIT | ERRINT_CMD_CRC_BIT |\ ++ ERRINT_CMD_ENDBIT_BIT | ERRINT_CMD_INDEX_BIT) ++#define ERRINT_DATA_ERRS (ERRINT_DATA_TIMEOUT_BIT | ERRINT_DATA_CRC_BIT |\ ++ ERRINT_DATA_ENDBIT_BIT | ERRINT_ADMA_BIT) ++#define ERRINT_TRANSFER_ERRS (ERRINT_CMD_ERRS | ERRINT_DATA_ERRS) ++ ++/* SD_WakeupCntr_BlockGapCntrl : Offset 0x02A , size = bytes */ ++/* SD_ClockCntrl : Offset 0x02C , size = bytes */ ++/* SD_SoftwareReset_TimeoutCntrl : Offset 0x02E , size = bytes */ ++/* SD_IntrStatus : Offset 0x030 , size = bytes */ ++/* SD_ErrorIntrStatus : Offset 0x032 , size = bytes */ ++/* SD_IntrStatusEnable : Offset 0x034 , size = bytes */ ++/* SD_ErrorIntrStatusEnable : Offset 0x036 , size = bytes */ ++/* SD_IntrSignalEnable : Offset 0x038 , size = bytes */ ++/* SD_ErrorIntrSignalEnable : Offset 0x03A , size = bytes */ ++/* SD_CMD12ErrorStatus : Offset 0x03C , size = bytes */ ++/* SD_Capabilities : Offset 0x040 , size = bytes */ ++/* SD_MaxCurCap : Offset 0x048 , size = bytes */ ++/* SD_MaxCurCap_Reserved: Offset 0x04C , size = bytes */ ++/* SD_SlotInterruptStatus: Offset 0x0FC , size = bytes */ ++/* SD_HostControllerVersion : Offset 0x0FE , size = bytes */ ++ ++/* SDIO Host Control Register DMA Mode Definitions */ ++#define SDIOH_SDMA_MODE 0 ++#define SDIOH_ADMA1_MODE 1 ++#define SDIOH_ADMA2_MODE 2 ++#define SDIOH_ADMA2_64_MODE 3 ++ ++#define ADMA2_ATTRIBUTE_VALID (1 << 0) /* ADMA Descriptor line valid */ ++#define ADMA2_ATTRIBUTE_END (1 << 1) /* End of Descriptor */ ++#define ADMA2_ATTRIBUTE_INT (1 << 2) /* Interrupt when line is done */ ++#define ADMA2_ATTRIBUTE_ACT_NOP (0 << 4) /* Skip current line, go to next. */ ++#define ADMA2_ATTRIBUTE_ACT_RSV (1 << 4) /* Same as NOP */ ++#define ADMA1_ATTRIBUTE_ACT_SET (1 << 4) /* ADMA1 Only - set transfer length */ ++#define ADMA2_ATTRIBUTE_ACT_TRAN (2 << 4) /* Transfer Data of one descriptor line. */ ++#define ADMA2_ATTRIBUTE_ACT_LINK (3 << 4) /* Link Descriptor */ ++ ++/* ADMA2 Descriptor Table Entry for 32-bit Address */ ++typedef struct adma2_dscr_32b { ++ uint32 len_attr; ++ uint32 phys_addr; ++} adma2_dscr_32b_t; ++ ++/* ADMA1 Descriptor Table Entry */ ++typedef struct adma1_dscr { ++ uint32 phys_addr_attr; ++} adma1_dscr_t; ++ ++#endif /* _SDIOH_H */ +diff --git a/drivers/net/wireless/ap6211/include/sdiovar.h b/drivers/net/wireless/ap6211/include/sdiovar.h +new file mode 100755 +index 0000000..83f82de +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/sdiovar.h +@@ -0,0 +1,58 @@ ++/* ++ * Structure used by apps whose drivers access SDIO drivers. ++ * Pulled out separately so dhdu and wlu can both use it. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sdiovar.h 241182 2011-02-17 21:50:03Z $ ++ */ ++ ++#ifndef _sdiovar_h_ ++#define _sdiovar_h_ ++ ++#include ++ ++/* require default structure packing */ ++#define BWL_DEFAULT_PACKING ++#include ++ ++typedef struct sdreg { ++ int func; ++ int offset; ++ int value; ++} sdreg_t; ++ ++/* Common msglevel constants */ ++#define SDH_ERROR_VAL 0x0001 /* Error */ ++#define SDH_TRACE_VAL 0x0002 /* Trace */ ++#define SDH_INFO_VAL 0x0004 /* Info */ ++#define SDH_DEBUG_VAL 0x0008 /* Debug */ ++#define SDH_DATA_VAL 0x0010 /* Data */ ++#define SDH_CTRL_VAL 0x0020 /* Control Regs */ ++#define SDH_LOG_VAL 0x0040 /* Enable bcmlog */ ++#define SDH_DMA_VAL 0x0080 /* DMA */ ++ ++#define NUM_PREV_TRANSACTIONS 16 ++ ++ ++#include ++ ++#endif /* _sdiovar_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/siutils.h b/drivers/net/wireless/ap6211/include/siutils.h +new file mode 100755 +index 0000000..acc72ee +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/siutils.h +@@ -0,0 +1,347 @@ ++/* ++ * Misc utility routines for accessing the SOC Interconnects ++ * of Broadcom HNBU chips. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: siutils.h 347614 2012-07-27 10:24:51Z $ ++ */ ++ ++#ifndef _siutils_h_ ++#define _siutils_h_ ++ ++/* ++ * Data structure to export all chip specific common variables ++ * public (read-only) portion of siutils handle returned by si_attach()/si_kattach() ++ */ ++struct si_pub { ++ uint socitype; /* SOCI_SB, SOCI_AI */ ++ ++ uint bustype; /* SI_BUS, PCI_BUS */ ++ uint buscoretype; /* PCI_CORE_ID, PCIE_CORE_ID, PCMCIA_CORE_ID */ ++ uint buscorerev; /* buscore rev */ ++ uint buscoreidx; /* buscore index */ ++ int ccrev; /* chip common core rev */ ++ uint32 cccaps; /* chip common capabilities */ ++ uint32 cccaps_ext; /* chip common capabilities extension */ ++ int pmurev; /* pmu core rev */ ++ uint32 pmucaps; /* pmu capabilities */ ++ uint boardtype; /* board type */ ++ uint boardrev; /* board rev */ ++ uint boardvendor; /* board vendor */ ++ uint boardflags; /* board flags */ ++ uint boardflags2; /* board flags2 */ ++ uint chip; /* chip number */ ++ uint chiprev; /* chip revision */ ++ uint chippkg; /* chip package option */ ++ uint32 chipst; /* chip status */ ++ bool issim; /* chip is in simulation or emulation */ ++ uint socirev; /* SOC interconnect rev */ ++ bool pci_pr32414; ++ ++}; ++ ++/* for HIGH_ONLY driver, the si_t must be writable to allow states sync from BMAC to HIGH driver ++ * for monolithic driver, it is readonly to prevent accident change ++ */ ++typedef const struct si_pub si_t; ++ ++ ++/* ++ * Many of the routines below take an 'sih' handle as their first arg. ++ * Allocate this by calling si_attach(). Free it by calling si_detach(). ++ * At any one time, the sih is logically focused on one particular si core ++ * (the "current core"). ++ * Use si_setcore() or si_setcoreidx() to change the association to another core. ++ */ ++#define SI_OSH NULL /* Use for si_kattach when no osh is available */ ++ ++#define BADIDX (SI_MAXCORES + 1) ++ ++/* clkctl xtal what flags */ ++#define XTAL 0x1 /* primary crystal oscillator (2050) */ ++#define PLL 0x2 /* main chip pll */ ++ ++/* clkctl clk mode */ ++#define CLK_FAST 0 /* force fast (pll) clock */ ++#define CLK_DYNAMIC 2 /* enable dynamic clock control */ ++ ++/* GPIO usage priorities */ ++#define GPIO_DRV_PRIORITY 0 /* Driver */ ++#define GPIO_APP_PRIORITY 1 /* Application */ ++#define GPIO_HI_PRIORITY 2 /* Highest priority. Ignore GPIO reservation */ ++ ++/* GPIO pull up/down */ ++#define GPIO_PULLUP 0 ++#define GPIO_PULLDN 1 ++ ++/* GPIO event regtype */ ++#define GPIO_REGEVT 0 /* GPIO register event */ ++#define GPIO_REGEVT_INTMSK 1 /* GPIO register event int mask */ ++#define GPIO_REGEVT_INTPOL 2 /* GPIO register event int polarity */ ++ ++/* device path */ ++#define SI_DEVPATH_BUFSZ 16 /* min buffer size in bytes */ ++ ++/* SI routine enumeration: to be used by update function with multiple hooks */ ++#define SI_DOATTACH 1 ++#define SI_PCIDOWN 2 ++#define SI_PCIUP 3 ++ ++#define ISSIM_ENAB(sih) 0 ++ ++/* PMU clock/power control */ ++#if defined(BCMPMUCTL) ++#define PMUCTL_ENAB(sih) (BCMPMUCTL) ++#else ++#define PMUCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PMU) ++#endif ++ ++/* chipcommon clock/power control (exclusive with PMU's) */ ++#if defined(BCMPMUCTL) && BCMPMUCTL ++#define CCCTL_ENAB(sih) (0) ++#define CCPLL_ENAB(sih) (0) ++#else ++#define CCCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PWR_CTL) ++#define CCPLL_ENAB(sih) ((sih)->cccaps & CC_CAP_PLL_MASK) ++#endif ++ ++typedef void (*gpio_handler_t)(uint32 stat, void *arg); ++/* External BT Coex enable mask */ ++#define CC_BTCOEX_EN_MASK 0x01 ++/* External PA enable mask */ ++#define GPIO_CTRL_EPA_EN_MASK 0x40 ++/* WL/BT control enable mask */ ++#define GPIO_CTRL_5_6_EN_MASK 0x60 ++#define GPIO_CTRL_7_6_EN_MASK 0xC0 ++#define GPIO_OUT_7_EN_MASK 0x80 ++ ++ ++/* CR4 specific defines used by the host driver */ ++#define SI_CR4_CAP (0x04) ++#define SI_CR4_BANKIDX (0x40) ++#define SI_CR4_BANKINFO (0x44) ++ ++#define ARMCR4_TCBBNB_MASK 0xf0 ++#define ARMCR4_TCBBNB_SHIFT 4 ++#define ARMCR4_TCBANB_MASK 0xf ++#define ARMCR4_TCBANB_SHIFT 0 ++ ++#define SICF_CPUHALT (0x0020) ++#define ARMCR4_BSZ_MASK 0x3f ++#define ARMCR4_BSZ_MULT 8192 ++ ++ ++/* === exported functions === */ ++extern si_t *si_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, ++ void *sdh, char **vars, uint *varsz); ++extern si_t *si_kattach(osl_t *osh); ++extern void si_detach(si_t *sih); ++extern bool si_pci_war16165(si_t *sih); ++ ++extern uint si_corelist(si_t *sih, uint coreid[]); ++extern uint si_coreid(si_t *sih); ++extern uint si_flag(si_t *sih); ++extern uint si_intflag(si_t *sih); ++extern uint si_coreidx(si_t *sih); ++extern uint si_coreunit(si_t *sih); ++extern uint si_corevendor(si_t *sih); ++extern uint si_corerev(si_t *sih); ++extern void *si_osh(si_t *sih); ++extern void si_setosh(si_t *sih, osl_t *osh); ++extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); ++extern void *si_coreregs(si_t *sih); ++extern uint si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); ++extern uint32 si_core_cflags(si_t *sih, uint32 mask, uint32 val); ++extern void si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); ++extern uint32 si_core_sflags(si_t *sih, uint32 mask, uint32 val); ++extern bool si_iscoreup(si_t *sih); ++extern uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit); ++extern void *si_setcoreidx(si_t *sih, uint coreidx); ++extern void *si_setcore(si_t *sih, uint coreid, uint coreunit); ++extern void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val); ++extern void si_restore_core(si_t *sih, uint coreid, uint intr_val); ++extern int si_numaddrspaces(si_t *sih); ++extern uint32 si_addrspace(si_t *sih, uint asidx); ++extern uint32 si_addrspacesize(si_t *sih, uint asidx); ++extern void si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); ++extern int si_corebist(si_t *sih); ++extern void si_core_reset(si_t *sih, uint32 bits, uint32 resetbits); ++extern void si_core_disable(si_t *sih, uint32 bits); ++extern uint32 si_clock_rate(uint32 pll_type, uint32 n, uint32 m); ++extern bool si_read_pmu_autopll(si_t *sih); ++extern uint32 si_clock(si_t *sih); ++extern uint32 si_alp_clock(si_t *sih); ++extern uint32 si_ilp_clock(si_t *sih); ++extern void si_pci_setup(si_t *sih, uint coremask); ++extern void si_pcmcia_init(si_t *sih); ++extern void si_setint(si_t *sih, int siflag); ++extern bool si_backplane64(si_t *sih); ++extern void si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, ++ void *intrsenabled_fn, void *intr_arg); ++extern void si_deregister_intr_callback(si_t *sih); ++extern void si_clkctl_init(si_t *sih); ++extern uint16 si_clkctl_fast_pwrup_delay(si_t *sih); ++extern bool si_clkctl_cc(si_t *sih, uint mode); ++extern int si_clkctl_xtal(si_t *sih, uint what, bool on); ++extern uint32 si_gpiotimerval(si_t *sih, uint32 mask, uint32 val); ++extern void si_btcgpiowar(si_t *sih); ++extern bool si_deviceremoved(si_t *sih); ++extern uint32 si_socram_size(si_t *sih); ++extern uint32 si_socdevram_size(si_t *sih); ++extern uint32 si_socram_srmem_size(si_t *sih); ++extern void si_socdevram(si_t *sih, bool set, uint8 *ennable, uint8 *protect, uint8 *remap); ++extern bool si_socdevram_pkg(si_t *sih); ++extern bool si_socdevram_remap_isenb(si_t *sih); ++extern uint32 si_socdevram_remap_size(si_t *sih); ++ ++extern void si_watchdog(si_t *sih, uint ticks); ++extern void si_watchdog_ms(si_t *sih, uint32 ms); ++extern uint32 si_watchdog_msticks(void); ++extern void *si_gpiosetcore(si_t *sih); ++extern uint32 si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority); ++extern uint32 si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority); ++extern uint32 si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority); ++extern uint32 si_gpioin(si_t *sih); ++extern uint32 si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority); ++extern uint32 si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority); ++extern uint32 si_gpioled(si_t *sih, uint32 mask, uint32 val); ++extern uint32 si_gpioreserve(si_t *sih, uint32 gpio_num, uint8 priority); ++extern uint32 si_gpiorelease(si_t *sih, uint32 gpio_num, uint8 priority); ++extern uint32 si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val); ++extern uint32 si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val); ++extern uint32 si_gpio_int_enable(si_t *sih, bool enable); ++ ++/* GPIO event handlers */ ++extern void *si_gpio_handler_register(si_t *sih, uint32 e, bool lev, gpio_handler_t cb, void *arg); ++extern void si_gpio_handler_unregister(si_t *sih, void* gpioh); ++extern void si_gpio_handler_process(si_t *sih); ++ ++/* Wake-on-wireless-LAN (WOWL) */ ++extern bool si_pci_pmecap(si_t *sih); ++struct osl_info; ++extern bool si_pci_fastpmecap(struct osl_info *osh); ++extern bool si_pci_pmestat(si_t *sih); ++extern void si_pci_pmeclr(si_t *sih); ++extern void si_pci_pmeen(si_t *sih); ++extern void si_pci_pmestatclr(si_t *sih); ++extern uint si_pcie_readreg(void *sih, uint addrtype, uint offset); ++ ++extern void si_sdio_init(si_t *sih); ++ ++extern uint16 si_d11_devid(si_t *sih); ++extern int si_corepciid(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevice, ++ uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif, uint8 *pciheader); ++ ++#define si_eci(sih) 0 ++static INLINE void * si_eci_init(si_t *sih) {return NULL;} ++#define si_eci_notify_bt(sih, type, val) (0) ++#define si_seci(sih) 0 ++#define si_seci_upd(sih, a) do {} while (0) ++static INLINE void * si_seci_init(si_t *sih, uint8 use_seci) {return NULL;} ++#define si_seci_down(sih) do {} while (0) ++ ++/* OTP status */ ++extern bool si_is_otp_disabled(si_t *sih); ++extern bool si_is_otp_powered(si_t *sih); ++extern void si_otp_power(si_t *sih, bool on); ++ ++/* SPROM availability */ ++extern bool si_is_sprom_available(si_t *sih); ++extern bool si_is_sprom_enabled(si_t *sih); ++extern void si_sprom_enable(si_t *sih, bool enable); ++ ++/* OTP/SROM CIS stuff */ ++extern int si_cis_source(si_t *sih); ++#define CIS_DEFAULT 0 ++#define CIS_SROM 1 ++#define CIS_OTP 2 ++ ++/* Fab-id information */ ++#define DEFAULT_FAB 0x0 /* Original/first fab used for this chip */ ++#define CSM_FAB7 0x1 /* CSM Fab7 chip */ ++#define TSMC_FAB12 0x2 /* TSMC Fab12/Fab14 chip */ ++#define SMIC_FAB4 0x3 /* SMIC Fab4 chip */ ++extern int si_otp_fabid(si_t *sih, uint16 *fabid, bool rw); ++extern uint16 si_fabid(si_t *sih); ++ ++/* ++ * Build device path. Path size must be >= SI_DEVPATH_BUFSZ. ++ * The returned path is NULL terminated and has trailing '/'. ++ * Return 0 on success, nonzero otherwise. ++ */ ++extern int si_devpath(si_t *sih, char *path, int size); ++/* Read variable with prepending the devpath to the name */ ++extern char *si_getdevpathvar(si_t *sih, const char *name); ++extern int si_getdevpathintvar(si_t *sih, const char *name); ++extern char *si_coded_devpathvar(si_t *sih, char *varname, int var_len, const char *name); ++ ++ ++extern uint8 si_pcieclkreq(si_t *sih, uint32 mask, uint32 val); ++extern uint32 si_pcielcreg(si_t *sih, uint32 mask, uint32 val); ++extern void si_war42780_clkreq(si_t *sih, bool clkreq); ++extern void si_pci_down(si_t *sih); ++extern void si_pci_up(si_t *sih); ++extern void si_pci_sleep(si_t *sih); ++extern void si_pcie_war_ovr_update(si_t *sih, uint8 aspm); ++extern void si_pcie_power_save_enable(si_t *sih, bool enable); ++extern void si_pcie_extendL1timer(si_t *sih, bool extend); ++extern int si_pci_fixcfg(si_t *sih); ++extern void si_chippkg_set(si_t *sih, uint); ++ ++extern void si_chipcontrl_btshd0_4331(si_t *sih, bool on); ++extern void si_chipcontrl_restore(si_t *sih, uint32 val); ++extern uint32 si_chipcontrl_read(si_t *sih); ++extern void si_chipcontrl_epa4331(si_t *sih, bool on); ++extern void si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl); ++extern void si_chipcontrl_srom4360(si_t *sih, bool on); ++/* Enable BT-COEX & Ex-PA for 4313 */ ++extern void si_epa_4313war(si_t *sih); ++extern void si_btc_enable_chipcontrol(si_t *sih); ++/* BT/WL selection for 4313 bt combo >= P250 boards */ ++extern void si_btcombo_p250_4313_war(si_t *sih); ++extern void si_btcombo_43228_war(si_t *sih); ++extern void si_clk_pmu_htavail_set(si_t *sih, bool set_clear); ++extern uint si_pll_reset(si_t *sih); ++/* === debug routines === */ ++ ++extern bool si_taclear(si_t *sih, bool details); ++ ++ ++ ++extern uint32 si_pciereg(si_t *sih, uint32 offset, uint32 mask, uint32 val, uint type); ++extern uint32 si_pcieserdesreg(si_t *sih, uint32 mdioslave, uint32 offset, uint32 mask, uint32 val); ++extern void si_pcie_set_request_size(si_t *sih, uint16 size); ++extern uint16 si_pcie_get_request_size(si_t *sih); ++extern uint16 si_pcie_get_ssid(si_t *sih); ++extern uint32 si_pcie_get_bar0(si_t *sih); ++extern int si_pcie_configspace_cache(si_t *sih); ++extern int si_pcie_configspace_restore(si_t *sih); ++extern int si_pcie_configspace_get(si_t *sih, uint8 *buf, uint size); ++ ++char *si_getnvramflvar(si_t *sih, const char *name); ++ ++ ++extern uint32 si_tcm_size(si_t *sih); ++ ++extern int si_set_sromctl(si_t *sih, uint32 value); ++extern uint32 si_get_sromctl(si_t *sih); ++#endif /* _siutils_h_ */ +diff --git a/drivers/net/wireless/ap6211/include/trxhdr.h b/drivers/net/wireless/ap6211/include/trxhdr.h +new file mode 100755 +index 0000000..bf92a56 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/trxhdr.h +@@ -0,0 +1,53 @@ ++/* ++ * TRX image file header format. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: trxhdr.h 260898 2011-05-20 23:11:12Z $ ++ */ ++ ++#ifndef _TRX_HDR_H ++#define _TRX_HDR_H ++ ++#include ++ ++#define TRX_MAGIC 0x30524448 /* "HDR0" */ ++#define TRX_VERSION 1 /* Version 1 */ ++#define TRX_MAX_LEN 0x3B0000 /* Max length */ ++#define TRX_NO_HEADER 1 /* Do not write TRX header */ ++#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ ++#define TRX_EMBED_UCODE 0x8 /* Trx contains embedded ucode image */ ++#define TRX_ROMSIM_IMAGE 0x10 /* Trx contains ROM simulation image */ ++#define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed rtecdc.bin image */ ++#define TRX_MAX_OFFSET 3 /* Max number of individual files */ ++ ++struct trx_header { ++ uint32 magic; /* "HDR0" */ ++ uint32 len; /* Length of file including header */ ++ uint32 crc32; /* 32-bit CRC from flag_version to end of file */ ++ uint32 flag_version; /* 0:15 flags, 16:31 version */ ++ uint32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ ++}; ++ ++/* Compatibility */ ++typedef struct trx_header TRXHDR, *PTRXHDR; ++ ++#endif /* _TRX_HDR_H */ +diff --git a/drivers/net/wireless/ap6211/include/typedefs.h b/drivers/net/wireless/ap6211/include/typedefs.h +new file mode 100755 +index 0000000..fe1d162 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/typedefs.h +@@ -0,0 +1,343 @@ ++/* ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * $Id: typedefs.h 286783 2011-09-29 06:18:57Z $ ++ */ ++ ++#ifndef _TYPEDEFS_H_ ++#define _TYPEDEFS_H_ ++ ++#ifdef SITE_TYPEDEFS ++ ++/* ++ * Define SITE_TYPEDEFS in the compile to include a site-specific ++ * typedef file "site_typedefs.h". ++ * ++ * If SITE_TYPEDEFS is not defined, then the code section below makes ++ * inferences about the compile environment based on defined symbols and ++ * possibly compiler pragmas. ++ * ++ * Following these two sections is the Default Typedefs section. ++ * This section is only processed if USE_TYPEDEF_DEFAULTS is ++ * defined. This section has a default set of typedefs and a few ++ * preprocessor symbols (TRUE, FALSE, NULL, ...). ++ */ ++ ++#include "site_typedefs.h" ++ ++#else ++ ++/* ++ * Infer the compile environment based on preprocessor symbols and pragmas. ++ * Override type definitions as needed, and include configuration-dependent ++ * header files to define types. ++ */ ++ ++#ifdef __cplusplus ++ ++#define TYPEDEF_BOOL ++#ifndef FALSE ++#define FALSE false ++#endif ++#ifndef TRUE ++#define TRUE true ++#endif ++ ++#else /* ! __cplusplus */ ++ ++ ++#endif /* ! __cplusplus */ ++ ++#if defined(__x86_64__) ++#define TYPEDEF_UINTPTR ++typedef unsigned long long int uintptr; ++#endif ++ ++ ++ ++ ++ ++#if defined(_NEED_SIZE_T_) ++typedef long unsigned int size_t; ++#endif ++ ++ ++ ++ ++#if defined(__sparc__) ++#define TYPEDEF_ULONG ++#endif ++ ++ ++/* ++ * If this is either a Linux hybrid build or the per-port code of a hybrid build ++ * then use the Linux header files to get some of the typedefs. Otherwise, define ++ * them entirely in this file. We can't always define the types because we get ++ * a duplicate typedef error; there is no way to "undefine" a typedef. ++ * We know when it's per-port code because each file defines LINUX_PORT at the top. ++ */ ++#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) ++#define TYPEDEF_UINT ++#ifndef TARGETENV_android ++#define TYPEDEF_USHORT ++#define TYPEDEF_ULONG ++#endif /* TARGETENV_android */ ++#ifdef __KERNEL__ ++#include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) ++#define TYPEDEF_BOOL ++#endif /* >= 2.6.19 */ ++/* special detection for 2.6.18-128.7.1.0.1.el5 */ ++#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18)) ++#include ++#ifdef noinline_for_stack ++#define TYPEDEF_BOOL ++#endif ++#endif /* == 2.6.18 */ ++#endif /* __KERNEL__ */ ++#endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */ ++ ++ ++ ++ ++/* Do not support the (u)int64 types with strict ansi for GNU C */ ++#if defined(__GNUC__) && defined(__STRICT_ANSI__) ++#define TYPEDEF_INT64 ++#define TYPEDEF_UINT64 ++#endif ++ ++/* ICL accepts unsigned 64 bit type only, and complains in ANSI mode ++ * for signed or unsigned ++ */ ++#if defined(__ICL) ++ ++#define TYPEDEF_INT64 ++ ++#if defined(__STDC__) ++#define TYPEDEF_UINT64 ++#endif ++ ++#endif /* __ICL */ ++ ++#if !defined(__DJGPP__) ++ ++/* pick up ushort & uint from standard types.h */ ++#if defined(__KERNEL__) ++ ++/* See note above */ ++#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) ++#include /* sys/types.h and linux/types.h are oil and water */ ++#endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */ ++ ++#else ++ ++ ++#include ++ ++#endif /* linux && __KERNEL__ */ ++ ++#endif ++ ++ ++ ++/* use the default typedefs in the next section of this file */ ++#define USE_TYPEDEF_DEFAULTS ++ ++#endif /* SITE_TYPEDEFS */ ++ ++ ++/* ++ * Default Typedefs ++ */ ++ ++#ifdef USE_TYPEDEF_DEFAULTS ++#undef USE_TYPEDEF_DEFAULTS ++ ++#ifndef TYPEDEF_BOOL ++typedef /* @abstract@ */ unsigned char bool; ++#endif ++ ++/* define uchar, ushort, uint, ulong */ ++ ++#ifndef TYPEDEF_UCHAR ++typedef unsigned char uchar; ++#endif ++ ++#ifndef TYPEDEF_USHORT ++typedef unsigned short ushort; ++#endif ++ ++#ifndef TYPEDEF_UINT ++typedef unsigned int uint; ++#endif ++ ++#ifndef TYPEDEF_ULONG ++typedef unsigned long ulong; ++#endif ++ ++/* define [u]int8/16/32/64, uintptr */ ++ ++#ifndef TYPEDEF_UINT8 ++typedef unsigned char uint8; ++#endif ++ ++#ifndef TYPEDEF_UINT16 ++typedef unsigned short uint16; ++#endif ++ ++#ifndef TYPEDEF_UINT32 ++typedef unsigned int uint32; ++#endif ++ ++#ifndef TYPEDEF_UINT64 ++typedef unsigned long long uint64; ++#endif ++ ++#ifndef TYPEDEF_UINTPTR ++typedef unsigned int uintptr; ++#endif ++ ++#ifndef TYPEDEF_INT8 ++typedef signed char int8; ++#endif ++ ++#ifndef TYPEDEF_INT16 ++typedef signed short int16; ++#endif ++ ++#ifndef TYPEDEF_INT32 ++typedef signed int int32; ++#endif ++ ++#ifndef TYPEDEF_INT64 ++typedef signed long long int64; ++#endif ++ ++/* define float32/64, float_t */ ++ ++#ifndef TYPEDEF_FLOAT32 ++typedef float float32; ++#endif ++ ++#ifndef TYPEDEF_FLOAT64 ++typedef double float64; ++#endif ++ ++/* ++ * abstracted floating point type allows for compile time selection of ++ * single or double precision arithmetic. Compiling with -DFLOAT32 ++ * selects single precision; the default is double precision. ++ */ ++ ++#ifndef TYPEDEF_FLOAT_T ++ ++#if defined(FLOAT32) ++typedef float32 float_t; ++#else /* default to double precision floating point */ ++typedef float64 float_t; ++#endif ++ ++#endif /* TYPEDEF_FLOAT_T */ ++ ++/* define macro values */ ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++#ifndef TRUE ++#define TRUE 1 /* TRUE */ ++#endif ++ ++#ifndef NULL ++#define NULL 0 ++#endif ++ ++#ifndef OFF ++#define OFF 0 ++#endif ++ ++#ifndef ON ++#define ON 1 /* ON = 1 */ ++#endif ++ ++#define AUTO (-1) /* Auto = -1 */ ++ ++/* define PTRSZ, INLINE */ ++ ++#ifndef PTRSZ ++#define PTRSZ sizeof(char*) ++#endif ++ ++ ++/* Detect compiler type. */ ++#if defined(__GNUC__) || defined(__lint) ++ #define BWL_COMPILER_GNU ++#elif defined(__CC_ARM) && __CC_ARM ++ #define BWL_COMPILER_ARMCC ++#else ++ #error "Unknown compiler!" ++#endif ++ ++ ++#ifndef INLINE ++ #if defined(BWL_COMPILER_MICROSOFT) ++ #define INLINE __inline ++ #elif defined(BWL_COMPILER_GNU) ++ #define INLINE __inline__ ++ #elif defined(BWL_COMPILER_ARMCC) ++ #define INLINE __inline ++ #else ++ #define INLINE ++ #endif ++#endif /* INLINE */ ++ ++#undef TYPEDEF_BOOL ++#undef TYPEDEF_UCHAR ++#undef TYPEDEF_USHORT ++#undef TYPEDEF_UINT ++#undef TYPEDEF_ULONG ++#undef TYPEDEF_UINT8 ++#undef TYPEDEF_UINT16 ++#undef TYPEDEF_UINT32 ++#undef TYPEDEF_UINT64 ++#undef TYPEDEF_UINTPTR ++#undef TYPEDEF_INT8 ++#undef TYPEDEF_INT16 ++#undef TYPEDEF_INT32 ++#undef TYPEDEF_INT64 ++#undef TYPEDEF_FLOAT32 ++#undef TYPEDEF_FLOAT64 ++#undef TYPEDEF_FLOAT_T ++ ++#endif /* USE_TYPEDEF_DEFAULTS */ ++ ++/* Suppress unused parameter warning */ ++#define UNUSED_PARAMETER(x) (void)(x) ++ ++/* Avoid warning for discarded const or volatile qualifier in special cases (-Wcast-qual) */ ++#define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr)) ++ ++/* ++ * Including the bcmdefs.h here, to make sure everyone including typedefs.h ++ * gets this automatically ++*/ ++#include ++#endif /* _TYPEDEFS_H_ */ +diff --git a/drivers/net/wireless/ap6211/include/wlfc_proto.h b/drivers/net/wireless/ap6211/include/wlfc_proto.h +new file mode 100755 +index 0000000..98d2fa9 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/wlfc_proto.h +@@ -0,0 +1,217 @@ ++/* ++* Copyright (C) 1999-2012, Broadcom Corporation ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2 (the "GPL"), ++* available at http://www.broadcom.com/licenses/GPLv2.php, with the ++* following added to such license: ++* ++* As a special exception, the copyright holders of this software give you ++* permission to link this software with independent modules, and to copy and ++* distribute the resulting executable under terms of your choice, provided that ++* you also meet, for each linked independent module, the terms and conditions of ++* the license of that module. An independent module is a module which is not ++* derived from this software. The special exception does not apply to any ++* modifications of the software. ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a license ++* other than the GPL, without Broadcom's express prior written consent. ++* $Id: wlfc_proto.h 361006 2012-10-05 07:45:51Z $ ++* ++*/ ++#ifndef __wlfc_proto_definitions_h__ ++#define __wlfc_proto_definitions_h__ ++ ++ /* Use TLV to convey WLFC information. ++ --------------------------------------------------------------------------- ++ | Type | Len | value | Description ++ --------------------------------------------------------------------------- ++ | 1 | 1 | (handle) | MAC OPEN ++ --------------------------------------------------------------------------- ++ | 2 | 1 | (handle) | MAC CLOSE ++ --------------------------------------------------------------------------- ++ | 3 | 2 | (count, handle, prec_bmp)| Set the credit depth for a MAC dstn ++ --------------------------------------------------------------------------- ++ | 4 | 4 | see pkttag comments | TXSTATUS ++ --------------------------------------------------------------------------- ++ | 5 | 4 | see pkttag comments | PKKTTAG [host->firmware] ++ --------------------------------------------------------------------------- ++ | 6 | 8 | (handle, ifid, MAC) | MAC ADD ++ --------------------------------------------------------------------------- ++ | 7 | 8 | (handle, ifid, MAC) | MAC DEL ++ --------------------------------------------------------------------------- ++ | 8 | 1 | (rssi) | RSSI - RSSI value for the packet. ++ --------------------------------------------------------------------------- ++ | 9 | 1 | (interface ID) | Interface OPEN ++ --------------------------------------------------------------------------- ++ | 10 | 1 | (interface ID) | Interface CLOSE ++ --------------------------------------------------------------------------- ++ | 11 | 8 | fifo credit returns map | FIFO credits back to the host ++ | | | | ++ | | | | -------------------------------------- ++ | | | | | ac0 | ac1 | ac2 | ac3 | bcmc | atim | ++ | | | | -------------------------------------- ++ | | | | ++ --------------------------------------------------------------------------- ++ | 12 | 2 | MAC handle, | Host provides a bitmap of pending ++ | | | AC[0-3] traffic bitmap | unicast traffic for MAC-handle dstn. ++ | | | | [host->firmware] ++ --------------------------------------------------------------------------- ++ | 13 | 3 | (count, handle, prec_bmp)| One time request for packet to a specific ++ | | | | MAC destination. ++ --------------------------------------------------------------------------- ++ | 15 | 1 | interface ID | NIC period start ++ --------------------------------------------------------------------------- ++ | 16 | 1 | interface ID | NIC period end ++ --------------------------------------------------------------------------- ++ | 17 | 3 | (ifid, txs) | Action frame tx status ++ --------------------------------------------------------------------------- ++ | 255 | N/A | N/A | FILLER - This is a special type ++ | | | | that has no length or value. ++ | | | | Typically used for padding. ++ --------------------------------------------------------------------------- ++ */ ++ ++#define WLFC_CTL_TYPE_MAC_OPEN 1 ++#define WLFC_CTL_TYPE_MAC_CLOSE 2 ++#define WLFC_CTL_TYPE_MAC_REQUEST_CREDIT 3 ++#define WLFC_CTL_TYPE_TXSTATUS 4 ++#define WLFC_CTL_TYPE_PKTTAG 5 ++ ++#define WLFC_CTL_TYPE_MACDESC_ADD 6 ++#define WLFC_CTL_TYPE_MACDESC_DEL 7 ++#define WLFC_CTL_TYPE_RSSI 8 ++ ++#define WLFC_CTL_TYPE_INTERFACE_OPEN 9 ++#define WLFC_CTL_TYPE_INTERFACE_CLOSE 10 ++ ++#define WLFC_CTL_TYPE_FIFO_CREDITBACK 11 ++ ++#define WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP 12 ++#define WLFC_CTL_TYPE_MAC_REQUEST_PACKET 13 ++#define WLFC_CTL_TYPE_HOST_REORDER_RXPKTS 14 ++ ++#define WLFC_CTL_TYPE_NIC_PRD_START 15 ++#define WLFC_CTL_TYPE_NIC_PRD_END 16 ++#define WLFC_CTL_TYPE_AF_TXS 17 ++#define WLFC_CTL_TYPE_TRANS_ID 18 ++#define WLFC_CTL_TYPE_COMP_TXSTATUS 19 ++ ++#define WLFC_CTL_TYPE_FILLER 255 ++ ++#define WLFC_CTL_VALUE_LEN_MACDESC 8 /* handle, interface, MAC */ ++ ++#define WLFC_CTL_VALUE_LEN_MAC 1 /* MAC-handle */ ++#define WLFC_CTL_VALUE_LEN_RSSI 1 ++ ++#define WLFC_CTL_VALUE_LEN_INTERFACE 1 ++#define WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP 2 ++ ++#define WLFC_CTL_VALUE_LEN_TXSTATUS 4 ++#define WLFC_CTL_VALUE_LEN_PKTTAG 4 ++ ++/* enough space to host all 4 ACs, bc/mc and atim fifo credit */ ++#define WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK 6 ++ ++#define WLFC_CTL_VALUE_LEN_REQUEST_CREDIT 3 /* credit, MAC-handle, prec_bitmap */ ++#define WLFC_CTL_VALUE_LEN_REQUEST_PACKET 3 /* credit, MAC-handle, prec_bitmap */ ++ ++#define WLFC_CTL_VALUE_LEN_NIC_PRD_START 1 ++#define WLFC_CTL_VALUE_LEN_NIC_PRD_END 1 ++#define WLFC_CTL_VALUE_LEN_AF_TXS 3 ++ ++ ++#define WLFC_PKTID_GEN_MASK 0x80000000 ++#define WLFC_PKTID_GEN_SHIFT 31 ++ ++#define WLFC_PKTID_GEN(x) (((x) & WLFC_PKTID_GEN_MASK) >> WLFC_PKTID_GEN_SHIFT) ++#define WLFC_PKTID_SETGEN(x, gen) (x) = ((x) & ~WLFC_PKTID_GEN_MASK) | \ ++ (((gen) << WLFC_PKTID_GEN_SHIFT) & WLFC_PKTID_GEN_MASK) ++ ++#define WLFC_PKTFLAG_PKTFROMHOST 0x01 ++#define WLFC_PKTFLAG_PKT_REQUESTED 0x02 ++ ++#define WL_TXSTATUS_FLAGS_MASK 0xf /* allow 4 bits only */ ++#define WL_TXSTATUS_FLAGS_SHIFT 27 ++ ++#define WL_TXSTATUS_SET_FLAGS(x, flags) ((x) = \ ++ ((x) & ~(WL_TXSTATUS_FLAGS_MASK << WL_TXSTATUS_FLAGS_SHIFT)) | \ ++ (((flags) & WL_TXSTATUS_FLAGS_MASK) << WL_TXSTATUS_FLAGS_SHIFT)) ++#define WL_TXSTATUS_GET_FLAGS(x) (((x) >> WL_TXSTATUS_FLAGS_SHIFT) & \ ++ WL_TXSTATUS_FLAGS_MASK) ++ ++#define WL_TXSTATUS_FIFO_MASK 0x7 /* allow 3 bits for FIFO ID */ ++#define WL_TXSTATUS_FIFO_SHIFT 24 ++ ++#define WL_TXSTATUS_SET_FIFO(x, flags) ((x) = \ ++ ((x) & ~(WL_TXSTATUS_FIFO_MASK << WL_TXSTATUS_FIFO_SHIFT)) | \ ++ (((flags) & WL_TXSTATUS_FIFO_MASK) << WL_TXSTATUS_FIFO_SHIFT)) ++#define WL_TXSTATUS_GET_FIFO(x) (((x) >> WL_TXSTATUS_FIFO_SHIFT) & WL_TXSTATUS_FIFO_MASK) ++ ++#define WL_TXSTATUS_PKTID_MASK 0xffffff /* allow 24 bits */ ++#define WL_TXSTATUS_SET_PKTID(x, num) ((x) = \ ++ ((x) & ~WL_TXSTATUS_PKTID_MASK) | (num)) ++#define WL_TXSTATUS_GET_PKTID(x) ((x) & WL_TXSTATUS_PKTID_MASK) ++ ++/* 32 STA should be enough??, 6 bits; Must be power of 2 */ ++#define WLFC_MAC_DESC_TABLE_SIZE 32 ++#define WLFC_MAX_IFNUM 16 ++#define WLFC_MAC_DESC_ID_INVALID 0xff ++ ++/* b[7:5] -reuse guard, b[4:0] -value */ ++#define WLFC_MAC_DESC_GET_LOOKUP_INDEX(x) ((x) & 0x1f) ++ ++#define WLFC_PKTFLAG_SET_PKTREQUESTED(x) (x) |= \ ++ (WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT) ++ ++#define WLFC_PKTFLAG_CLR_PKTREQUESTED(x) (x) &= \ ++ ~(WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT) ++ ++#define WL_TXSTATUS_GENERATION_MASK 1 ++#define WL_TXSTATUS_GENERATION_SHIFT 31 ++ ++#define WLFC_PKTFLAG_SET_GENERATION(x, gen) ((x) = \ ++ ((x) & ~(WL_TXSTATUS_GENERATION_MASK << WL_TXSTATUS_GENERATION_SHIFT)) | \ ++ (((gen) & WL_TXSTATUS_GENERATION_MASK) << WL_TXSTATUS_GENERATION_SHIFT)) ++ ++#define WLFC_PKTFLAG_GENERATION(x) (((x) >> WL_TXSTATUS_GENERATION_SHIFT) & \ ++ WL_TXSTATUS_GENERATION_MASK) ++ ++#define WLFC_MAX_PENDING_DATALEN 120 ++ ++/* host is free to discard the packet */ ++#define WLFC_CTL_PKTFLAG_DISCARD 0 ++/* D11 suppressed a packet */ ++#define WLFC_CTL_PKTFLAG_D11SUPPRESS 1 ++/* WL firmware suppressed a packet because MAC is ++ already in PSMode (short time window) ++*/ ++#define WLFC_CTL_PKTFLAG_WLSUPPRESS 2 ++/* Firmware tossed this packet */ ++#define WLFC_CTL_PKTFLAG_TOSSED_BYWLC 3 ++ ++#define WLFC_D11_STATUS_INTERPRET(txs) \ ++ (((txs)->status.suppr_ind != 0) ? WLFC_CTL_PKTFLAG_D11SUPPRESS : WLFC_CTL_PKTFLAG_DISCARD) ++ ++/* AMPDU host reorder packet flags */ ++#define WLHOST_REORDERDATA_MAXFLOWS 256 ++#define WLHOST_REORDERDATA_LEN 10 ++#define WLHOST_REORDERDATA_TOTLEN (WLHOST_REORDERDATA_LEN + 1 + 1) /* +tag +len */ ++ ++#define WLHOST_REORDERDATA_FLOWID_OFFSET 0 ++#define WLHOST_REORDERDATA_MAXIDX_OFFSET 2 ++#define WLHOST_REORDERDATA_FLAGS_OFFSET 4 ++#define WLHOST_REORDERDATA_CURIDX_OFFSET 6 ++#define WLHOST_REORDERDATA_EXPIDX_OFFSET 8 ++ ++#define WLHOST_REORDERDATA_DEL_FLOW 0x01 ++#define WLHOST_REORDERDATA_FLUSH_ALL 0x02 ++#define WLHOST_REORDERDATA_CURIDX_VALID 0x04 ++#define WLHOST_REORDERDATA_EXPIDX_VALID 0x08 ++#define WLHOST_REORDERDATA_NEW_HOLE 0x10 ++/* transaction id data len byte 0: rsvd, byte 1: seqnumber, byte 2-5 will be used for timestampe */ ++#define WLFC_CTL_TRANS_ID_LEN 6 ++ ++#endif /* __wlfc_proto_definitions_h__ */ +diff --git a/drivers/net/wireless/ap6211/include/wlioctl.h b/drivers/net/wireless/ap6211/include/wlioctl.h +new file mode 100755 +index 0000000..a3e7003 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/include/wlioctl.h +@@ -0,0 +1,5079 @@ ++/* ++ * Custom OID/ioctl definitions for ++ * Broadcom 802.11abg Networking Device Driver ++ * ++ * Definitions subject to change without notice. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wlioctl.h 366141 2012-11-01 01:55:06Z $ ++ */ ++ ++#ifndef _wlioctl_h_ ++#define _wlioctl_h_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++#include ++#include ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* LINUX_POSTMOGRIFY_REMOVAL: undefined during compile phase, so its ++ * a no-op for most cases. For hybrid and other open source releases, ++ * its defined during a second pass and mogrified out for distribution. ++ */ ++ ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++ ++#ifndef INTF_NAME_SIZ ++#define INTF_NAME_SIZ 16 ++#endif ++ ++/* Used to send ioctls over the transport pipe */ ++typedef struct remote_ioctl { ++ cdc_ioctl_t msg; ++ uint data_len; ++ char intf_name[INTF_NAME_SIZ]; ++} rem_ioctl_t; ++#define REMOTE_SIZE sizeof(rem_ioctl_t) ++ ++#define ACTION_FRAME_SIZE 1800 ++ ++typedef struct wl_action_frame { ++ struct ether_addr da; ++ uint16 len; ++ uint32 packetId; ++ uint8 data[ACTION_FRAME_SIZE]; ++} wl_action_frame_t; ++ ++#define WL_WIFI_ACTION_FRAME_SIZE sizeof(struct wl_action_frame) ++ ++typedef struct ssid_info ++{ ++ uint8 ssid_len; /* the length of SSID */ ++ uint8 ssid[32]; /* SSID string */ ++} ssid_info_t; ++ ++typedef struct wl_af_params { ++ uint32 channel; ++ int32 dwell_time; ++ struct ether_addr BSSID; ++ wl_action_frame_t action_frame; ++} wl_af_params_t; ++ ++#define WL_WIFI_AF_PARAMS_SIZE sizeof(struct wl_af_params) ++ ++#define MFP_TEST_FLAG_NORMAL 0 ++#define MFP_TEST_FLAG_ANY_KEY 1 ++typedef struct wl_sa_query { ++ uint32 flag; ++ uint8 action; ++ uint16 id; ++ struct ether_addr da; ++} wl_sa_query_t; ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* require default structure packing */ ++#define BWL_DEFAULT_PACKING ++#include ++ ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++/* Legacy structure to help keep backward compatible wl tool and tray app */ ++ ++#define LEGACY_WL_BSS_INFO_VERSION 107 /* older version of wl_bss_info struct */ ++ ++typedef struct wl_bss_info_107 { ++ uint32 version; /* version field */ ++ uint32 length; /* byte length of data in this record, ++ * starting at version and including IEs ++ */ ++ struct ether_addr BSSID; ++ uint16 beacon_period; /* units are Kusec */ ++ uint16 capability; /* Capability information */ ++ uint8 SSID_len; ++ uint8 SSID[32]; ++ struct { ++ uint count; /* # rates in this set */ ++ uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ ++ } rateset; /* supported rates */ ++ uint8 channel; /* Channel no. */ ++ uint16 atim_window; /* units are Kusec */ ++ uint8 dtim_period; /* DTIM period */ ++ int16 RSSI; /* receive signal strength (in dBm) */ ++ int8 phy_noise; /* noise (in dBm) */ ++ uint32 ie_length; /* byte length of Information Elements */ ++ /* variable length Information Elements */ ++} wl_bss_info_107_t; ++ ++/* ++ * Per-BSS information structure. ++ */ ++ ++#define LEGACY2_WL_BSS_INFO_VERSION 108 /* old version of wl_bss_info struct */ ++ ++/* BSS info structure ++ * Applications MUST CHECK ie_offset field and length field to access IEs and ++ * next bss_info structure in a vector (in wl_scan_results_t) ++ */ ++typedef struct wl_bss_info_108 { ++ uint32 version; /* version field */ ++ uint32 length; /* byte length of data in this record, ++ * starting at version and including IEs ++ */ ++ struct ether_addr BSSID; ++ uint16 beacon_period; /* units are Kusec */ ++ uint16 capability; /* Capability information */ ++ uint8 SSID_len; ++ uint8 SSID[32]; ++ struct { ++ uint count; /* # rates in this set */ ++ uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ ++ } rateset; /* supported rates */ ++ chanspec_t chanspec; /* chanspec for bss */ ++ uint16 atim_window; /* units are Kusec */ ++ uint8 dtim_period; /* DTIM period */ ++ int16 RSSI; /* receive signal strength (in dBm) */ ++ int8 phy_noise; /* noise (in dBm) */ ++ ++ uint8 n_cap; /* BSS is 802.11N Capable */ ++ uint32 nbss_cap; /* 802.11N BSS Capabilities (based on HT_CAP_*) */ ++ uint8 ctl_ch; /* 802.11N BSS control channel number */ ++ uint32 reserved32[1]; /* Reserved for expansion of BSS properties */ ++ uint8 flags; /* flags */ ++ uint8 reserved[3]; /* Reserved for expansion of BSS properties */ ++ uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ ++ ++ uint16 ie_offset; /* offset at which IEs start, from beginning */ ++ uint32 ie_length; /* byte length of Information Elements */ ++ /* Add new fields here */ ++ /* variable length Information Elements */ ++} wl_bss_info_108_t; ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++#define WL_BSS_INFO_VERSION 109 /* current version of wl_bss_info struct */ ++ ++/* BSS info structure ++ * Applications MUST CHECK ie_offset field and length field to access IEs and ++ * next bss_info structure in a vector (in wl_scan_results_t) ++ */ ++typedef struct wl_bss_info { ++ uint32 version; /* version field */ ++ uint32 length; /* byte length of data in this record, ++ * starting at version and including IEs ++ */ ++ struct ether_addr BSSID; ++ uint16 beacon_period; /* units are Kusec */ ++ uint16 capability; /* Capability information */ ++ uint8 SSID_len; ++ uint8 SSID[32]; ++ struct { ++ uint count; /* # rates in this set */ ++ uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ ++ } rateset; /* supported rates */ ++ chanspec_t chanspec; /* chanspec for bss */ ++ uint16 atim_window; /* units are Kusec */ ++ uint8 dtim_period; /* DTIM period */ ++ int16 RSSI; /* receive signal strength (in dBm) */ ++ int8 phy_noise; /* noise (in dBm) */ ++ ++ uint8 n_cap; /* BSS is 802.11N Capable */ ++ uint32 nbss_cap; /* 802.11N+AC BSS Capabilities */ ++ uint8 ctl_ch; /* 802.11N BSS control channel number */ ++ uint8 padding1[3]; /* explicit struct alignment padding */ ++ uint16 vht_rxmcsmap; /* VHT rx mcs map */ ++ uint16 vht_txmcsmap; /* VHT tx mcs map */ ++ uint8 flags; /* flags */ ++ uint8 vht_cap; /* BSS is vht capable */ ++ uint8 reserved[2]; /* Reserved for expansion of BSS properties */ ++ uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ ++ ++ uint16 ie_offset; /* offset at which IEs start, from beginning */ ++ uint32 ie_length; /* byte length of Information Elements */ ++ int16 SNR; /* average SNR of during frame reception */ ++ /* Add new fields here */ ++ /* variable length Information Elements */ ++} wl_bss_info_t; ++ ++/* bss_info_cap_t flags */ ++#define WL_BSS_FLAGS_FROM_BEACON 0x01 /* bss_info derived from beacon */ ++#define WL_BSS_FLAGS_FROM_CACHE 0x02 /* bss_info collected from cache */ ++#define WL_BSS_FLAGS_RSSI_ONCHANNEL 0x04 /* rssi info was received on channel (vs offchannel) */ ++ ++/* bssinfo flag for nbss_cap */ ++#define VHT_BI_SGI_80MHZ 0x00000100 ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++ ++typedef struct wl_bsscfg { ++ uint32 wsec; ++ uint32 WPA_auth; ++ uint32 wsec_index; ++ uint32 associated; ++ uint32 BSS; ++ uint32 phytest_on; ++ struct ether_addr prev_BSSID; ++ struct ether_addr BSSID; ++ uint32 targetbss_wpa2_flags; ++ uint32 assoc_type; ++ uint32 assoc_state; ++} wl_bsscfg_t; ++ ++typedef struct wl_bss_config { ++ uint32 atim_window; ++ uint32 beacon_period; ++ uint32 chanspec; ++} wl_bss_config_t; ++ ++#define DLOAD_HANDLER_VER 1 /* Downloader version */ ++#define DLOAD_FLAG_VER_MASK 0xf000 /* Downloader version mask */ ++#define DLOAD_FLAG_VER_SHIFT 12 /* Downloader version shift */ ++ ++#define DL_CRC_NOT_INUSE 0x0001 ++ ++/* generic download types & flags */ ++enum { ++ DL_TYPE_UCODE = 1, ++ DL_TYPE_CLM = 2 ++}; ++ ++/* ucode type values */ ++enum { ++ UCODE_FW, ++ INIT_VALS, ++ BS_INIT_VALS ++}; ++ ++struct wl_dload_data { ++ uint16 flag; ++ uint16 dload_type; ++ uint32 len; ++ uint32 crc; ++ uint8 data[1]; ++}; ++typedef struct wl_dload_data wl_dload_data_t; ++ ++struct wl_ucode_info { ++ uint32 ucode_type; ++ uint32 num_chunks; ++ uint32 chunk_len; ++ uint32 chunk_num; ++ uint8 data_chunk[1]; ++}; ++typedef struct wl_ucode_info wl_ucode_info_t; ++ ++struct wl_clm_dload_info { ++ uint32 ds_id; ++ uint32 clm_total_len; ++ uint32 num_chunks; ++ uint32 chunk_len; ++ uint32 chunk_offset; ++ uint8 data_chunk[1]; ++}; ++typedef struct wl_clm_dload_info wl_clm_dload_info_t; ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++typedef struct wlc_ssid { ++ uint32 SSID_len; ++ uchar SSID[32]; ++} wlc_ssid_t; ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++ ++#define MAX_PREFERRED_AP_NUM 5 ++typedef struct wlc_fastssidinfo { ++ uint32 SSID_channel[MAX_PREFERRED_AP_NUM]; ++ wlc_ssid_t SSID_info[MAX_PREFERRED_AP_NUM]; ++} wlc_fastssidinfo_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct wnm_url { ++ uint8 len; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT wnm_url_t; ++ ++typedef struct chan_scandata { ++ uint8 txpower; ++ uint8 pad; ++ chanspec_t channel; /* Channel num, bw, ctrl_sb and band */ ++ uint32 channel_mintime; ++ uint32 channel_maxtime; ++} chan_scandata_t; ++ ++typedef enum wl_scan_type { ++ EXTDSCAN_FOREGROUND_SCAN, ++ EXTDSCAN_BACKGROUND_SCAN, ++ EXTDSCAN_FORCEDBACKGROUND_SCAN ++} wl_scan_type_t; ++ ++#define WLC_EXTDSCAN_MAX_SSID 5 ++ ++typedef struct wl_extdscan_params { ++ int8 nprobes; /* 0, passive, otherwise active */ ++ int8 split_scan; /* split scan */ ++ int8 band; /* band */ ++ int8 pad; ++ wlc_ssid_t ssid[WLC_EXTDSCAN_MAX_SSID]; /* ssid list */ ++ uint32 tx_rate; /* in 500ksec units */ ++ wl_scan_type_t scan_type; /* enum */ ++ int32 channel_num; ++ chan_scandata_t channel_list[1]; /* list of chandata structs */ ++} wl_extdscan_params_t; ++ ++#define WL_EXTDSCAN_PARAMS_FIXED_SIZE (sizeof(wl_extdscan_params_t) - sizeof(chan_scandata_t)) ++ ++#define WL_BSSTYPE_INFRA 1 ++#define WL_BSSTYPE_INDEP 0 ++#define WL_BSSTYPE_ANY 2 ++ ++/* Bitmask for scan_type */ ++#define WL_SCANFLAGS_PASSIVE 0x01 /* force passive scan */ ++#define WL_SCANFLAGS_RESERVED 0x02 /* Reserved */ ++#define WL_SCANFLAGS_PROHIBITED 0x04 /* allow scanning prohibited channels */ ++ ++#define WL_SCAN_PARAMS_SSID_MAX 10 ++ ++typedef struct wl_scan_params { ++ wlc_ssid_t ssid; /* default: {0, ""} */ ++ struct ether_addr bssid; /* default: bcast */ ++ int8 bss_type; /* default: any, ++ * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT ++ */ ++ uint8 scan_type; /* flags, 0 use default */ ++ int32 nprobes; /* -1 use default, number of probes per channel */ ++ int32 active_time; /* -1 use default, dwell time per channel for ++ * active scanning ++ */ ++ int32 passive_time; /* -1 use default, dwell time per channel ++ * for passive scanning ++ */ ++ int32 home_time; /* -1 use default, dwell time for the home channel ++ * between channel scans ++ */ ++ int32 channel_num; /* count of channels and ssids that follow ++ * ++ * low half is count of channels in channel_list, 0 ++ * means default (use all available channels) ++ * ++ * high half is entries in wlc_ssid_t array that ++ * follows channel_list, aligned for int32 (4 bytes) ++ * meaning an odd channel count implies a 2-byte pad ++ * between end of channel_list and first ssid ++ * ++ * if ssid count is zero, single ssid in the fixed ++ * parameter portion is assumed, otherwise ssid in ++ * the fixed portion is ignored ++ */ ++ uint16 channel_list[1]; /* list of chanspecs */ ++} wl_scan_params_t; ++ ++/* size of wl_scan_params not including variable length array */ ++#define WL_SCAN_PARAMS_FIXED_SIZE 64 ++ ++/* masks for channel and ssid count */ ++#define WL_SCAN_PARAMS_COUNT_MASK 0x0000ffff ++#define WL_SCAN_PARAMS_NSSID_SHIFT 16 ++ ++#define WL_SCAN_ACTION_START 1 ++#define WL_SCAN_ACTION_CONTINUE 2 ++#define WL_SCAN_ACTION_ABORT 3 ++ ++#define ISCAN_REQ_VERSION 1 ++ ++/* incremental scan struct */ ++typedef struct wl_iscan_params { ++ uint32 version; ++ uint16 action; ++ uint16 scan_duration; ++ wl_scan_params_t params; ++} wl_iscan_params_t; ++ ++/* 3 fields + size of wl_scan_params, not including variable length array */ ++#define WL_ISCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_iscan_params_t, params) + sizeof(wlc_ssid_t)) ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++typedef struct wl_scan_results { ++ uint32 buflen; ++ uint32 version; ++ uint32 count; ++ wl_bss_info_t bss_info[1]; ++} wl_scan_results_t; ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++/* size of wl_scan_results not including variable length array */ ++#define WL_SCAN_RESULTS_FIXED_SIZE (sizeof(wl_scan_results_t) - sizeof(wl_bss_info_t)) ++ ++/* wl_iscan_results status values */ ++#define WL_SCAN_RESULTS_SUCCESS 0 ++#define WL_SCAN_RESULTS_PARTIAL 1 ++#define WL_SCAN_RESULTS_PENDING 2 ++#define WL_SCAN_RESULTS_ABORTED 3 ++#define WL_SCAN_RESULTS_NO_MEM 4 ++ ++/* Used in EXT_STA */ ++#define DNGL_RXCTXT_SIZE 45 ++ ++ ++#define ESCAN_REQ_VERSION 1 ++ ++typedef struct wl_escan_params { ++ uint32 version; ++ uint16 action; ++ uint16 sync_id; ++ wl_scan_params_t params; ++} wl_escan_params_t; ++ ++#define WL_ESCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_escan_params_t, params) + sizeof(wlc_ssid_t)) ++ ++typedef struct wl_escan_result { ++ uint32 buflen; ++ uint32 version; ++ uint16 sync_id; ++ uint16 bss_count; ++ wl_bss_info_t bss_info[1]; ++} wl_escan_result_t; ++ ++#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(wl_escan_result_t) - sizeof(wl_bss_info_t)) ++ ++/* incremental scan results struct */ ++typedef struct wl_iscan_results { ++ uint32 status; ++ wl_scan_results_t results; ++} wl_iscan_results_t; ++ ++/* size of wl_iscan_results not including variable length array */ ++#define WL_ISCAN_RESULTS_FIXED_SIZE \ ++ (WL_SCAN_RESULTS_FIXED_SIZE + OFFSETOF(wl_iscan_results_t, results)) ++ ++typedef struct wl_probe_params { ++ wlc_ssid_t ssid; ++ struct ether_addr bssid; ++ struct ether_addr mac; ++} wl_probe_params_t; ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++#define WL_MAXRATES_IN_SET 16 /* max # of rates in a rateset */ ++typedef struct wl_rateset { ++ uint32 count; /* # rates in this set */ ++ uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ ++} wl_rateset_t; ++ ++typedef struct wl_rateset_args { ++ uint32 count; /* # rates in this set */ ++ uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ ++ uint8 mcs[MCSSET_LEN]; /* supported mcs index bit map */ ++} wl_rateset_args_t; ++ ++/* uint32 list */ ++typedef struct wl_uint32_list { ++ /* in - # of elements, out - # of entries */ ++ uint32 count; ++ /* variable length uint32 list */ ++ uint32 element[1]; ++} wl_uint32_list_t; ++ ++/* used for association with a specific BSSID and chanspec list */ ++typedef struct wl_assoc_params { ++ struct ether_addr bssid; /* 00:00:00:00:00:00: broadcast scan */ ++ uint16 bssid_cnt; /* 0: use chanspec_num, and the single bssid, ++ * otherwise count of chanspecs in chanspec_list ++ * AND paired bssids following chanspec_list ++ */ ++ int32 chanspec_num; /* 0: all available channels, ++ * otherwise count of chanspecs in chanspec_list ++ */ ++ chanspec_t chanspec_list[1]; /* list of chanspecs */ ++} wl_assoc_params_t; ++#define WL_ASSOC_PARAMS_FIXED_SIZE OFFSETOF(wl_assoc_params_t, chanspec_list) ++ ++/* used for reassociation/roam to a specific BSSID and channel */ ++typedef wl_assoc_params_t wl_reassoc_params_t; ++#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE ++ ++/* used for association to a specific BSSID and channel */ ++typedef wl_assoc_params_t wl_join_assoc_params_t; ++#define WL_JOIN_ASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE ++ ++/* used for join with or without a specific bssid and channel list */ ++typedef struct wl_join_params { ++ wlc_ssid_t ssid; ++ wl_assoc_params_t params; /* optional field, but it must include the fixed portion ++ * of the wl_assoc_params_t struct when it does present. ++ */ ++} wl_join_params_t; ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++#define WL_JOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_join_params_t, params) + \ ++ WL_ASSOC_PARAMS_FIXED_SIZE) ++/* scan params for extended join */ ++typedef struct wl_join_scan_params { ++ uint8 scan_type; /* 0 use default, active or passive scan */ ++ int32 nprobes; /* -1 use default, number of probes per channel */ ++ int32 active_time; /* -1 use default, dwell time per channel for ++ * active scanning ++ */ ++ int32 passive_time; /* -1 use default, dwell time per channel ++ * for passive scanning ++ */ ++ int32 home_time; /* -1 use default, dwell time for the home channel ++ * between channel scans ++ */ ++} wl_join_scan_params_t; ++ ++/* extended join params */ ++typedef struct wl_extjoin_params { ++ wlc_ssid_t ssid; /* {0, ""}: wildcard scan */ ++ wl_join_scan_params_t scan; ++ wl_join_assoc_params_t assoc; /* optional field, but it must include the fixed portion ++ * of the wl_join_assoc_params_t struct when it does ++ * present. ++ */ ++} wl_extjoin_params_t; ++#define WL_EXTJOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_extjoin_params_t, assoc) + \ ++ WL_JOIN_ASSOC_PARAMS_FIXED_SIZE) ++ ++/* All builds use the new 11ac ratespec/chanspec */ ++#undef D11AC_IOTYPES ++#define D11AC_IOTYPES ++ ++#ifndef D11AC_IOTYPES ++ ++/* defines used by the nrate iovar */ ++#define NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */ ++#define NRATE_RATE_MASK 0x0000007f /* rate/mcs value */ ++#define NRATE_STF_MASK 0x0000ff00 /* stf mode mask: siso, cdd, stbc, sdm */ ++#define NRATE_STF_SHIFT 8 /* stf mode shift */ ++#define NRATE_OVERRIDE 0x80000000 /* bit indicates override both rate & mode */ ++#define NRATE_OVERRIDE_MCS_ONLY 0x40000000 /* bit indicate to override mcs only */ ++#define NRATE_SGI_MASK 0x00800000 /* sgi mode */ ++#define NRATE_SGI_SHIFT 23 /* sgi mode */ ++#define NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */ ++#define NRATE_LDPC_SHIFT 22 /* ldpc shift */ ++ ++#define NRATE_STF_SISO 0 /* stf mode SISO */ ++#define NRATE_STF_CDD 1 /* stf mode CDD */ ++#define NRATE_STF_STBC 2 /* stf mode STBC */ ++#define NRATE_STF_SDM 3 /* stf mode SDM */ ++ ++#else /* D11AC_IOTYPES */ ++ ++/* WL_RSPEC defines for rate information */ ++#define WL_RSPEC_RATE_MASK 0x000000FF /* rate or HT MCS value */ ++#define WL_RSPEC_VHT_MCS_MASK 0x0000000F /* VHT MCS value */ ++#define WL_RSPEC_VHT_NSS_MASK 0x000000F0 /* VHT Nss value */ ++#define WL_RSPEC_VHT_NSS_SHIFT 4 /* VHT Nss value shift */ ++#define WL_RSPEC_TXEXP_MASK 0x00000300 ++#define WL_RSPEC_TXEXP_SHIFT 8 ++#define WL_RSPEC_BW_MASK 0x00070000 /* bandwidth mask */ ++#define WL_RSPEC_BW_SHIFT 16 /* bandwidth shift */ ++#define WL_RSPEC_STBC 0x00100000 /* STBC encoding, Nsts = 2 x Nss */ ++#define WL_RSPEC_LDPC 0x00400000 /* bit indicates adv coding in use */ ++#define WL_RSPEC_SGI 0x00800000 /* Short GI mode */ ++#define WL_RSPEC_ENCODING_MASK 0x03000000 /* Encoding of Rate/MCS field */ ++#define WL_RSPEC_OVERRIDE_RATE 0x40000000 /* bit indicate to override mcs only */ ++#define WL_RSPEC_OVERRIDE_MODE 0x80000000 /* bit indicates override both rate & mode */ ++ ++/* WL_RSPEC_ENCODING field defs */ ++#define WL_RSPEC_ENCODE_RATE 0x00000000 /* Legacy rate is stored in RSPEC_RATE_MASK */ ++#define WL_RSPEC_ENCODE_HT 0x01000000 /* HT MCS is stored in RSPEC_RATE_MASK */ ++#define WL_RSPEC_ENCODE_VHT 0x02000000 /* VHT MCS and Nss is stored in RSPEC_RATE_MASK */ ++ ++/* WL_RSPEC_BW field defs */ ++#define WL_RSPEC_BW_UNSPECIFIED 0 ++#define WL_RSPEC_BW_20MHZ 0x00010000 ++#define WL_RSPEC_BW_40MHZ 0x00020000 ++#define WL_RSPEC_BW_80MHZ 0x00030000 ++#define WL_RSPEC_BW_160MHZ 0x00040000 ++ ++/* Legacy defines for the nrate iovar */ ++#define OLD_NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */ ++#define OLD_NRATE_RATE_MASK 0x0000007f /* rate/mcs value */ ++#define OLD_NRATE_STF_MASK 0x0000ff00 /* stf mode mask: siso, cdd, stbc, sdm */ ++#define OLD_NRATE_STF_SHIFT 8 /* stf mode shift */ ++#define OLD_NRATE_OVERRIDE 0x80000000 /* bit indicates override both rate & mode */ ++#define OLD_NRATE_OVERRIDE_MCS_ONLY 0x40000000 /* bit indicate to override mcs only */ ++#define OLD_NRATE_SGI 0x00800000 /* sgi mode */ ++#define OLD_NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */ ++ ++#define OLD_NRATE_STF_SISO 0 /* stf mode SISO */ ++#define OLD_NRATE_STF_CDD 1 /* stf mode CDD */ ++#define OLD_NRATE_STF_STBC 2 /* stf mode STBC */ ++#define OLD_NRATE_STF_SDM 3 /* stf mode SDM */ ++ ++#endif /* D11AC_IOTYPES */ ++ ++#define ANTENNA_NUM_1 1 /* total number of antennas to be used */ ++#define ANTENNA_NUM_2 2 ++#define ANTENNA_NUM_3 3 ++#define ANTENNA_NUM_4 4 ++ ++#define ANT_SELCFG_AUTO 0x80 /* bit indicates antenna sel AUTO */ ++#define ANT_SELCFG_MASK 0x33 /* antenna configuration mask */ ++#define ANT_SELCFG_MAX 4 /* max number of antenna configurations */ ++#define ANT_SELCFG_TX_UNICAST 0 /* unicast tx antenna configuration */ ++#define ANT_SELCFG_RX_UNICAST 1 /* unicast rx antenna configuration */ ++#define ANT_SELCFG_TX_DEF 2 /* default tx antenna configuration */ ++#define ANT_SELCFG_RX_DEF 3 /* default rx antenna configuration */ ++ ++#define MAX_STREAMS_SUPPORTED 4 /* max number of streams supported */ ++ ++typedef struct { ++ uint8 ant_config[ANT_SELCFG_MAX]; /* antenna configuration */ ++ uint8 num_antcfg; /* number of available antenna configurations */ ++} wlc_antselcfg_t; ++ ++#define HIGHEST_SINGLE_STREAM_MCS 7 /* MCS values greater than this enable multiple streams */ ++ ++#define MAX_CCA_CHANNELS 38 /* Max number of 20 Mhz wide channels */ ++#define MAX_CCA_SECS 60 /* CCA keeps this many seconds history */ ++ ++#define IBSS_MED 15 /* Mediom in-bss congestion percentage */ ++#define IBSS_HI 25 /* Hi in-bss congestion percentage */ ++#define OBSS_MED 12 ++#define OBSS_HI 25 ++#define INTERFER_MED 5 ++#define INTERFER_HI 10 ++ ++#define CCA_FLAG_2G_ONLY 0x01 /* Return a channel from 2.4 Ghz band */ ++#define CCA_FLAG_5G_ONLY 0x02 /* Return a channel from 2.4 Ghz band */ ++#define CCA_FLAG_IGNORE_DURATION 0x04 /* Ignore dwell time for each channel */ ++#define CCA_FLAGS_PREFER_1_6_11 0x10 ++#define CCA_FLAG_IGNORE_INTERFER 0x20 /* do not exlude channel based on interfer level */ ++ ++#define CCA_ERRNO_BAND 1 /* After filtering for band pref, no choices left */ ++#define CCA_ERRNO_DURATION 2 /* After filtering for duration, no choices left */ ++#define CCA_ERRNO_PREF_CHAN 3 /* After filtering for chan pref, no choices left */ ++#define CCA_ERRNO_INTERFER 4 /* After filtering for interference, no choices left */ ++#define CCA_ERRNO_TOO_FEW 5 /* Only 1 channel was input */ ++ ++typedef struct { ++ uint32 duration; /* millisecs spent sampling this channel */ ++ uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ ++ /* move if cur bss moves channels) */ ++ uint32 congest_obss; /* traffic not in our bss */ ++ uint32 interference; /* millisecs detecting a non 802.11 interferer. */ ++ uint32 timestamp; /* second timestamp */ ++} cca_congest_t; ++ ++typedef struct { ++ chanspec_t chanspec; /* Which channel? */ ++ uint8 num_secs; /* How many secs worth of data */ ++ cca_congest_t secs[1]; /* Data */ ++} cca_congest_channel_req_t; ++ ++/* interference source detection and identification mode */ ++#define ITFR_MODE_DISABLE 0 /* disable feature */ ++#define ITFR_MODE_MANUAL_ENABLE 1 /* enable manual detection */ ++#define ITFR_MODE_AUTO_ENABLE 2 /* enable auto detection */ ++ ++/* interference sources */ ++enum interference_source { ++ ITFR_NONE = 0, /* interference */ ++ ITFR_PHONE, /* wireless phone */ ++ ITFR_VIDEO_CAMERA, /* wireless video camera */ ++ ITFR_MICROWAVE_OVEN, /* microwave oven */ ++ ITFR_BABY_MONITOR, /* wireless baby monitor */ ++ ITFR_BLUETOOTH, /* bluetooth */ ++ ITFR_VIDEO_CAMERA_OR_BABY_MONITOR, /* wireless camera or baby monitor */ ++ ITFR_BLUETOOTH_OR_BABY_MONITOR, /* bluetooth or baby monitor */ ++ ITFR_VIDEO_CAMERA_OR_PHONE, /* video camera or phone */ ++ ITFR_UNIDENTIFIED /* interference from unidentified source */ ++}; ++ ++/* structure for interference source report */ ++typedef struct { ++ uint32 flags; /* flags. bit definitions below */ ++ uint32 source; /* last detected interference source */ ++ uint32 timestamp; /* second timestamp on interferenced flag change */ ++} interference_source_rep_t; ++ ++/* bit definitions for flags in interference source report */ ++#define ITFR_INTERFERENCED 1 /* interference detected */ ++#define ITFR_HOME_CHANNEL 2 /* home channel has interference */ ++#define ITFR_NOISY_ENVIRONMENT 4 /* noisy environemnt so feature stopped */ ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++#define WLC_CNTRY_BUF_SZ 4 /* Country string is 3 bytes + NUL */ ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++ ++typedef struct wl_country { ++ char country_abbrev[WLC_CNTRY_BUF_SZ]; /* nul-terminated country code used in ++ * the Country IE ++ */ ++ int32 rev; /* revision specifier for ccode ++ * on set, -1 indicates unspecified. ++ * on get, rev >= 0 ++ */ ++ char ccode[WLC_CNTRY_BUF_SZ]; /* nul-terminated built-in country code. ++ * variable length, but fixed size in ++ * struct allows simple allocation for ++ * expected country strings <= 3 chars. ++ */ ++} wl_country_t; ++ ++typedef struct wl_channels_in_country { ++ uint32 buflen; ++ uint32 band; ++ char country_abbrev[WLC_CNTRY_BUF_SZ]; ++ uint32 count; ++ uint32 channel[1]; ++} wl_channels_in_country_t; ++ ++typedef struct wl_country_list { ++ uint32 buflen; ++ uint32 band_set; ++ uint32 band; ++ uint32 count; ++ char country_abbrev[1]; ++} wl_country_list_t; ++ ++#define WL_NUM_RPI_BINS 8 ++#define WL_RM_TYPE_BASIC 1 ++#define WL_RM_TYPE_CCA 2 ++#define WL_RM_TYPE_RPI 3 ++ ++#define WL_RM_FLAG_PARALLEL (1<<0) ++ ++#define WL_RM_FLAG_LATE (1<<1) ++#define WL_RM_FLAG_INCAPABLE (1<<2) ++#define WL_RM_FLAG_REFUSED (1<<3) ++ ++typedef struct wl_rm_req_elt { ++ int8 type; ++ int8 flags; ++ chanspec_t chanspec; ++ uint32 token; /* token for this measurement */ ++ uint32 tsf_h; /* TSF high 32-bits of Measurement start time */ ++ uint32 tsf_l; /* TSF low 32-bits */ ++ uint32 dur; /* TUs */ ++} wl_rm_req_elt_t; ++ ++typedef struct wl_rm_req { ++ uint32 token; /* overall measurement set token */ ++ uint32 count; /* number of measurement requests */ ++ void *cb; /* completion callback function: may be NULL */ ++ void *cb_arg; /* arg to completion callback function */ ++ wl_rm_req_elt_t req[1]; /* variable length block of requests */ ++} wl_rm_req_t; ++#define WL_RM_REQ_FIXED_LEN OFFSETOF(wl_rm_req_t, req) ++ ++typedef struct wl_rm_rep_elt { ++ int8 type; ++ int8 flags; ++ chanspec_t chanspec; ++ uint32 token; /* token for this measurement */ ++ uint32 tsf_h; /* TSF high 32-bits of Measurement start time */ ++ uint32 tsf_l; /* TSF low 32-bits */ ++ uint32 dur; /* TUs */ ++ uint32 len; /* byte length of data block */ ++ uint8 data[1]; /* variable length data block */ ++} wl_rm_rep_elt_t; ++#define WL_RM_REP_ELT_FIXED_LEN 24 /* length excluding data block */ ++ ++#define WL_RPI_REP_BIN_NUM 8 ++typedef struct wl_rm_rpi_rep { ++ uint8 rpi[WL_RPI_REP_BIN_NUM]; ++ int8 rpi_max[WL_RPI_REP_BIN_NUM]; ++} wl_rm_rpi_rep_t; ++ ++typedef struct wl_rm_rep { ++ uint32 token; /* overall measurement set token */ ++ uint32 len; /* length of measurement report block */ ++ wl_rm_rep_elt_t rep[1]; /* variable length block of reports */ ++} wl_rm_rep_t; ++#define WL_RM_REP_FIXED_LEN 8 ++ ++ ++typedef enum sup_auth_status { ++ /* Basic supplicant authentication states */ ++ WLC_SUP_DISCONNECTED = 0, ++ WLC_SUP_CONNECTING, ++ WLC_SUP_IDREQUIRED, ++ WLC_SUP_AUTHENTICATING, ++ WLC_SUP_AUTHENTICATED, ++ WLC_SUP_KEYXCHANGE, ++ WLC_SUP_KEYED, ++ WLC_SUP_TIMEOUT, ++ WLC_SUP_LAST_BASIC_STATE, ++ ++ /* Extended supplicant authentication states */ ++ /* Waiting to receive handshake msg M1 */ ++ WLC_SUP_KEYXCHANGE_WAIT_M1 = WLC_SUP_AUTHENTICATED, ++ /* Preparing to send handshake msg M2 */ ++ WLC_SUP_KEYXCHANGE_PREP_M2 = WLC_SUP_KEYXCHANGE, ++ /* Waiting to receive handshake msg M3 */ ++ WLC_SUP_KEYXCHANGE_WAIT_M3 = WLC_SUP_LAST_BASIC_STATE, ++ WLC_SUP_KEYXCHANGE_PREP_M4, /* Preparing to send handshake msg M4 */ ++ WLC_SUP_KEYXCHANGE_WAIT_G1, /* Waiting to receive handshake msg G1 */ ++ WLC_SUP_KEYXCHANGE_PREP_G2 /* Preparing to send handshake msg G2 */ ++} sup_auth_status_t; ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* Enumerate crypto algorithms */ ++#define CRYPTO_ALGO_OFF 0 ++#define CRYPTO_ALGO_WEP1 1 ++#define CRYPTO_ALGO_TKIP 2 ++#define CRYPTO_ALGO_WEP128 3 ++#define CRYPTO_ALGO_AES_CCM 4 ++#define CRYPTO_ALGO_AES_OCB_MSDU 5 ++#define CRYPTO_ALGO_AES_OCB_MPDU 6 ++#if !defined(BCMEXTCCX) ++#define CRYPTO_ALGO_NALG 7 ++#else ++#define CRYPTO_ALGO_CKIP 7 ++#define CRYPTO_ALGO_CKIP_MMH 8 ++#define CRYPTO_ALGO_WEP_MMH 9 ++#define CRYPTO_ALGO_NALG 10 ++#endif ++#ifdef BCMWAPI_WPI ++#define CRYPTO_ALGO_SMS4 11 ++#endif /* BCMWAPI_WPI */ ++#define CRYPTO_ALGO_PMK 12 /* for 802.1x supp to set PMK before 4-way */ ++ ++#define WSEC_GEN_MIC_ERROR 0x0001 ++#define WSEC_GEN_REPLAY 0x0002 ++#define WSEC_GEN_ICV_ERROR 0x0004 ++#define WSEC_GEN_MFP_ACT_ERROR 0x0008 ++#define WSEC_GEN_MFP_DISASSOC_ERROR 0x0010 ++#define WSEC_GEN_MFP_DEAUTH_ERROR 0x0020 ++ ++#define WL_SOFT_KEY (1 << 0) /* Indicates this key is using soft encrypt */ ++#define WL_PRIMARY_KEY (1 << 1) /* Indicates this key is the primary (ie tx) key */ ++#if defined(BCMEXTCCX) ++#define WL_CKIP_KP (1 << 4) /* CMIC */ ++#define WL_CKIP_MMH (1 << 5) /* CKIP */ ++#else ++#define WL_KF_RES_4 (1 << 4) /* Reserved for backward compat */ ++#define WL_KF_RES_5 (1 << 5) /* Reserved for backward compat */ ++#endif ++#define WL_IBSS_PEER_GROUP_KEY (1 << 6) /* Indicates a group key for a IBSS PEER */ ++ ++typedef struct wl_wsec_key { ++ uint32 index; /* key index */ ++ uint32 len; /* key length */ ++ uint8 data[DOT11_MAX_KEY_SIZE]; /* key data */ ++ uint32 pad_1[18]; ++ uint32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ ++ uint32 flags; /* misc flags */ ++ uint32 pad_2[2]; ++ int pad_3; ++ int iv_initialized; /* has IV been initialized already? */ ++ int pad_4; ++ /* Rx IV */ ++ struct { ++ uint32 hi; /* upper 32 bits of IV */ ++ uint16 lo; /* lower 16 bits of IV */ ++ } rxiv; ++ uint32 pad_5[2]; ++ struct ether_addr ea; /* per station */ ++} wl_wsec_key_t; ++ ++#define WSEC_MIN_PSK_LEN 8 ++#define WSEC_MAX_PSK_LEN 64 ++ ++/* Flag for key material needing passhash'ing */ ++#define WSEC_PASSPHRASE (1<<0) ++ ++/* receptacle for WLC_SET_WSEC_PMK parameter */ ++typedef struct { ++ ushort key_len; /* octets in key material */ ++ ushort flags; /* key handling qualification */ ++ uint8 key[WSEC_MAX_PSK_LEN]; /* PMK material */ ++} wsec_pmk_t; ++ ++/* wireless security bitvec */ ++#define WEP_ENABLED 0x0001 ++#define TKIP_ENABLED 0x0002 ++#define AES_ENABLED 0x0004 ++#define WSEC_SWFLAG 0x0008 ++#define SES_OW_ENABLED 0x0040 /* to go into transition mode without setting wep */ ++ ++/* wsec macros for operating on the above definitions */ ++#define WSEC_WEP_ENABLED(wsec) ((wsec) & WEP_ENABLED) ++#define WSEC_TKIP_ENABLED(wsec) ((wsec) & TKIP_ENABLED) ++#define WSEC_AES_ENABLED(wsec) ((wsec) & AES_ENABLED) ++ ++#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) ++#define WSEC_SES_OW_ENABLED(wsec) ((wsec) & SES_OW_ENABLED) ++#ifdef BCMWAPI_WPI ++#define SMS4_ENABLED 0x0100 ++#endif /* BCMWAPI_WPI */ ++ ++#ifdef MFP ++#define MFP_CAPABLE 0x0200 ++#define MFP_REQUIRED 0x0400 ++#define MFP_SHA256 0x0800 /* a special configuration for STA for WIFI test tool */ ++#endif /* MFP */ ++ ++/* WPA authentication mode bitvec */ ++#define WPA_AUTH_DISABLED 0x0000 /* Legacy (i.e., non-WPA) */ ++#define WPA_AUTH_NONE 0x0001 /* none (IBSS) */ ++#define WPA_AUTH_UNSPECIFIED 0x0002 /* over 802.1x */ ++#define WPA_AUTH_PSK 0x0004 /* Pre-shared key */ ++#if defined(BCMEXTCCX) ++#define WPA_AUTH_CCKM 0x0008 /* CCKM */ ++#define WPA2_AUTH_CCKM 0x0010 /* CCKM2 */ ++#endif ++/* #define WPA_AUTH_8021X 0x0020 */ /* 802.1x, reserved */ ++#define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */ ++#define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */ ++#define BRCM_AUTH_PSK 0x0100 /* BRCM specific PSK */ ++#define BRCM_AUTH_DPT 0x0200 /* DPT PSK without group keys */ ++#ifdef BCMWAPI_WAI ++#define WPA_AUTH_WAPI 0x0400 ++#define WAPI_AUTH_NONE WPA_AUTH_NONE /* none (IBSS) */ ++#define WAPI_AUTH_UNSPECIFIED 0x0400 /* over AS */ ++#define WAPI_AUTH_PSK 0x0800 /* Pre-shared key */ ++#endif /* BCMWAPI_WAI */ ++#define WPA2_AUTH_MFP 0x1000 /* MFP (11w) in contrast to CCX */ ++#define WPA2_AUTH_TPK 0x2000 /* TDLS Peer Key */ ++#define WPA2_AUTH_FT 0x4000 /* Fast Transition. */ ++#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ ++ ++/* pmkid */ ++#define MAXPMKID 16 ++ ++typedef struct _pmkid { ++ struct ether_addr BSSID; ++ uint8 PMKID[WPA2_PMKID_LEN]; ++} pmkid_t; ++ ++typedef struct _pmkid_list { ++ uint32 npmkid; ++ pmkid_t pmkid[1]; ++} pmkid_list_t; ++ ++typedef struct _pmkid_cand { ++ struct ether_addr BSSID; ++ uint8 preauth; ++} pmkid_cand_t; ++ ++typedef struct _pmkid_cand_list { ++ uint32 npmkid_cand; ++ pmkid_cand_t pmkid_cand[1]; ++} pmkid_cand_list_t; ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++typedef struct wl_assoc_info { ++ uint32 req_len; ++ uint32 resp_len; ++ uint32 flags; ++ struct dot11_assoc_req req; ++ struct ether_addr reassoc_bssid; /* used in reassoc's */ ++ struct dot11_assoc_resp resp; ++} wl_assoc_info_t; ++ ++/* flags */ ++#define WLC_ASSOC_REQ_IS_REASSOC 0x01 /* assoc req was actually a reassoc */ ++ ++typedef struct wl_led_info { ++ uint32 index; /* led index */ ++ uint32 behavior; ++ uint8 activehi; ++} wl_led_info_t; ++ ++ ++/* srom read/write struct passed through ioctl */ ++typedef struct { ++ uint byteoff; /* byte offset */ ++ uint nbytes; /* number of bytes */ ++ uint16 buf[1]; ++} srom_rw_t; ++ ++/* similar cis (srom or otp) struct [iovar: may not be aligned] */ ++typedef struct { ++ uint32 source; /* cis source */ ++ uint32 byteoff; /* byte offset */ ++ uint32 nbytes; /* number of bytes */ ++ /* data follows here */ ++} cis_rw_t; ++ ++#define WLC_CIS_DEFAULT 0 /* built-in default */ ++#define WLC_CIS_SROM 1 /* source is sprom */ ++#define WLC_CIS_OTP 2 /* source is otp */ ++ ++/* R_REG and W_REG struct passed through ioctl */ ++typedef struct { ++ uint32 byteoff; /* byte offset of the field in d11regs_t */ ++ uint32 val; /* read/write value of the field */ ++ uint32 size; /* sizeof the field */ ++ uint band; /* band (optional) */ ++} rw_reg_t; ++ ++/* Structure used by GET/SET_ATTEN ioctls - it controls power in b/g-band */ ++/* PCL - Power Control Loop */ ++/* current gain setting is replaced by user input */ ++#define WL_ATTEN_APP_INPUT_PCL_OFF 0 /* turn off PCL, apply supplied input */ ++#define WL_ATTEN_PCL_ON 1 /* turn on PCL */ ++/* current gain setting is maintained */ ++#define WL_ATTEN_PCL_OFF 2 /* turn off PCL. */ ++ ++typedef struct { ++ uint16 auto_ctrl; /* WL_ATTEN_XX */ ++ uint16 bb; /* Baseband attenuation */ ++ uint16 radio; /* Radio attenuation */ ++ uint16 txctl1; /* Radio TX_CTL1 value */ ++} atten_t; ++ ++/* Per-AC retry parameters */ ++struct wme_tx_params_s { ++ uint8 short_retry; ++ uint8 short_fallback; ++ uint8 long_retry; ++ uint8 long_fallback; ++ uint16 max_rate; /* In units of 512 Kbps */ ++}; ++ ++typedef struct wme_tx_params_s wme_tx_params_t; ++ ++#define WL_WME_TX_PARAMS_IO_BYTES (sizeof(wme_tx_params_t) * AC_COUNT) ++ ++/* defines used by poweridx iovar - it controls power in a-band */ ++/* current gain setting is maintained */ ++#define WL_PWRIDX_PCL_OFF -2 /* turn off PCL. */ ++#define WL_PWRIDX_PCL_ON -1 /* turn on PCL */ ++#define WL_PWRIDX_LOWER_LIMIT -2 /* lower limit */ ++#define WL_PWRIDX_UPPER_LIMIT 63 /* upper limit */ ++/* value >= 0 causes ++ * - input to be set to that value ++ * - PCL to be off ++ */ ++ ++/* Used to get specific link/ac parameters */ ++typedef struct { ++ int ac; ++ uint8 val; ++ struct ether_addr ea; ++} link_val_t; ++ ++#define BCM_MAC_STATUS_INDICATION (0x40010200L) ++ ++typedef struct { ++ uint16 ver; /* version of this struct */ ++ uint16 len; /* length in bytes of this structure */ ++ uint16 cap; /* sta's advertised capabilities */ ++ uint32 flags; /* flags defined below */ ++ uint32 idle; /* time since data pkt rx'd from sta */ ++ struct ether_addr ea; /* Station address */ ++ wl_rateset_t rateset; /* rateset in use */ ++ uint32 in; /* seconds elapsed since associated */ ++ uint32 listen_interval_inms; /* Min Listen interval in ms for this STA */ ++ uint32 tx_pkts; /* # of packets transmitted */ ++ uint32 tx_failures; /* # of packets failed */ ++ uint32 rx_ucast_pkts; /* # of unicast packets received */ ++ uint32 rx_mcast_pkts; /* # of multicast packets received */ ++ uint32 tx_rate; /* Rate of last successful tx frame */ ++ uint32 rx_rate; /* Rate of last successful rx frame */ ++ uint32 rx_decrypt_succeeds; /* # of packet decrypted successfully */ ++ uint32 rx_decrypt_failures; /* # of packet decrypted unsuccessfully */ ++} sta_info_t; ++ ++#define WL_OLD_STAINFO_SIZE OFFSETOF(sta_info_t, tx_pkts) ++ ++#define WL_STA_VER 3 ++ ++/* Flags for sta_info_t indicating properties of STA */ ++#define WL_STA_BRCM 0x1 /* Running a Broadcom driver */ ++#define WL_STA_WME 0x2 /* WMM association */ ++#define WL_STA_UNUSED 0x4 ++#define WL_STA_AUTHE 0x8 /* Authenticated */ ++#define WL_STA_ASSOC 0x10 /* Associated */ ++#define WL_STA_AUTHO 0x20 /* Authorized */ ++#define WL_STA_WDS 0x40 /* Wireless Distribution System */ ++#define WL_STA_WDS_LINKUP 0x80 /* WDS traffic/probes flowing properly */ ++#define WL_STA_PS 0x100 /* STA is in power save mode from AP's viewpoint */ ++#define WL_STA_APSD_BE 0x200 /* APSD delv/trigger for AC_BE is default enabled */ ++#define WL_STA_APSD_BK 0x400 /* APSD delv/trigger for AC_BK is default enabled */ ++#define WL_STA_APSD_VI 0x800 /* APSD delv/trigger for AC_VI is default enabled */ ++#define WL_STA_APSD_VO 0x1000 /* APSD delv/trigger for AC_VO is default enabled */ ++#define WL_STA_N_CAP 0x2000 /* STA 802.11n capable */ ++#define WL_STA_SCBSTATS 0x4000 /* Per STA debug stats */ ++ ++#define WL_WDS_LINKUP WL_STA_WDS_LINKUP /* deprecated */ ++ ++/* Values for TX Filter override mode */ ++#define WLC_TXFILTER_OVERRIDE_DISABLED 0 ++#define WLC_TXFILTER_OVERRIDE_ENABLED 1 ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* Used to get specific STA parameters */ ++typedef struct { ++ uint32 val; ++ struct ether_addr ea; ++} scb_val_t; ++ ++/* Used by iovar versions of some ioctls, i.e. WLC_SCB_AUTHORIZE et al */ ++typedef struct { ++ uint32 code; ++ scb_val_t ioctl_args; ++} authops_t; ++ ++/* channel encoding */ ++typedef struct channel_info { ++ int hw_channel; ++ int target_channel; ++ int scan_channel; ++} channel_info_t; ++ ++/* For ioctls that take a list of MAC addresses */ ++struct maclist { ++ uint count; /* number of MAC addresses */ ++ struct ether_addr ea[1]; /* variable length array of MAC addresses */ ++}; ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++/* get pkt count struct passed through ioctl */ ++typedef struct get_pktcnt { ++ uint rx_good_pkt; ++ uint rx_bad_pkt; ++ uint tx_good_pkt; ++ uint tx_bad_pkt; ++ uint rx_ocast_good_pkt; /* unicast packets destined for others */ ++} get_pktcnt_t; ++ ++/* NINTENDO2 */ ++#define LQ_IDX_MIN 0 ++#define LQ_IDX_MAX 1 ++#define LQ_IDX_AVG 2 ++#define LQ_IDX_SUM 2 ++#define LQ_IDX_LAST 3 ++#define LQ_STOP_MONITOR 0 ++#define LQ_START_MONITOR 1 ++ ++/* Get averages RSSI, Rx PHY rate and SNR values */ ++typedef struct { ++ int rssi[LQ_IDX_LAST]; /* Array to keep min, max, avg rssi */ ++ int snr[LQ_IDX_LAST]; /* Array to keep min, max, avg snr */ ++ int isvalid; /* Flag indicating whether above data is valid */ ++} wl_lq_t; /* Link Quality */ ++ ++typedef enum wl_wakeup_reason_type { ++ LCD_ON = 1, ++ LCD_OFF, ++ DRC1_WAKE, ++ DRC2_WAKE, ++ REASON_LAST ++} wl_wr_type_t; ++ ++typedef struct { ++/* Unique filter id */ ++ uint32 id; ++ ++/* stores the reason for the last wake up */ ++ uint8 reason; ++} wl_wr_t; ++ ++/* Get MAC specific rate histogram command */ ++typedef struct { ++ struct ether_addr ea; /* MAC Address */ ++ uint8 ac_cat; /* Access Category */ ++ uint8 num_pkts; /* Number of packet entries to be averaged */ ++} wl_mac_ratehisto_cmd_t; /* MAC Specific Rate Histogram command */ ++ ++/* Get MAC rate histogram response */ ++typedef struct { ++ uint32 rate[WLC_MAXRATE + 1]; /* Rates */ ++ uint32 mcs[WL_RATESET_SZ_HT_MCS * WL_TX_CHAINS_MAX]; /* MCS counts */ ++ uint32 vht[WL_RATESET_SZ_VHT_MCS][WL_TX_CHAINS_MAX]; /* VHT counts */ ++ uint32 tsf_timer[2][2]; /* Start and End time for 8bytes value */ ++} wl_mac_ratehisto_res_t; /* MAC Specific Rate Histogram Response */ ++ ++/* Values for TX Filter override mode */ ++#define WLC_TXFILTER_OVERRIDE_DISABLED 0 ++#define WLC_TXFILTER_OVERRIDE_ENABLED 1 ++ ++#define WL_IOCTL_ACTION_GET 0x0 ++#define WL_IOCTL_ACTION_SET 0x1 ++#define WL_IOCTL_ACTION_OVL_IDX_MASK 0x1e ++#define WL_IOCTL_ACTION_OVL_RSV 0x20 ++#define WL_IOCTL_ACTION_OVL 0x40 ++#define WL_IOCTL_ACTION_MASK 0x7e ++#define WL_IOCTL_ACTION_OVL_SHIFT 1 ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* Linux network driver ioctl encoding */ ++typedef struct wl_ioctl { ++ uint cmd; /* common ioctl definition */ ++ void *buf; /* pointer to user buffer */ ++ uint len; /* length of user buffer */ ++ uint8 set; /* 1=set IOCTL; 0=query IOCTL */ ++ uint used; /* bytes read or written (optional) */ ++ uint needed; /* bytes needed (optional) */ ++} wl_ioctl_t; ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++ ++/* reference to wl_ioctl_t struct used by usermode driver */ ++#define ioctl_subtype set /* subtype param */ ++#define ioctl_pid used /* pid param */ ++#define ioctl_status needed /* status param */ ++ ++/* ++ * Structure for passing hardware and software ++ * revision info up from the driver. ++ */ ++typedef struct wlc_rev_info { ++ uint vendorid; /* PCI vendor id */ ++ uint deviceid; /* device id of chip */ ++ uint radiorev; /* radio revision */ ++ uint chiprev; /* chip revision */ ++ uint corerev; /* core revision */ ++ uint boardid; /* board identifier (usu. PCI sub-device id) */ ++ uint boardvendor; /* board vendor (usu. PCI sub-vendor id) */ ++ uint boardrev; /* board revision */ ++ uint driverrev; /* driver version */ ++ uint ucoderev; /* microcode version */ ++ uint bus; /* bus type */ ++ uint chipnum; /* chip number */ ++ uint phytype; /* phy type */ ++ uint phyrev; /* phy revision */ ++ uint anarev; /* anacore rev */ ++ uint chippkg; /* chip package info */ ++} wlc_rev_info_t; ++ ++#define WL_REV_INFO_LEGACY_LENGTH 48 ++ ++#define WL_BRAND_MAX 10 ++typedef struct wl_instance_info { ++ uint instance; ++ char brand[WL_BRAND_MAX]; ++} wl_instance_info_t; ++ ++/* structure to change size of tx fifo */ ++typedef struct wl_txfifo_sz { ++ uint16 magic; ++ uint16 fifo; ++ uint16 size; ++} wl_txfifo_sz_t; ++/* magic pattern used for mismatch driver and wl */ ++#define WL_TXFIFO_SZ_MAGIC 0xa5a5 ++ ++/* Transfer info about an IOVar from the driver */ ++/* Max supported IOV name size in bytes, + 1 for nul termination */ ++#define WLC_IOV_NAME_LEN 30 ++typedef struct wlc_iov_trx_s { ++ uint8 module; ++ uint8 type; ++ char name[WLC_IOV_NAME_LEN]; ++} wlc_iov_trx_t; ++ ++/* check this magic number */ ++#define WLC_IOCTL_MAGIC 0x14e46c77 ++ ++/* bump this number if you change the ioctl interface */ ++#ifdef D11AC_IOTYPES ++#define WLC_IOCTL_VERSION 2 ++#define WLC_IOCTL_VERSION_LEGACY_IOTYPES 1 ++#else ++#define WLC_IOCTL_VERSION 1 ++#endif /* D11AC_IOTYPES */ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++#define WLC_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ ++#define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ ++#define WLC_IOCTL_MEDLEN 1536 /* "med" length ioctl buffer required */ ++#if defined(LCNCONF) || defined(LCN40CONF) ++#define WLC_SAMPLECOLLECT_MAXLEN 8192 /* Max Sample Collect buffer */ ++#else ++#define WLC_SAMPLECOLLECT_MAXLEN 10240 /* Max Sample Collect buffer for two cores */ ++#endif ++ ++/* common ioctl definitions */ ++#define WLC_GET_MAGIC 0 ++#define WLC_GET_VERSION 1 ++#define WLC_UP 2 ++#define WLC_DOWN 3 ++#define WLC_GET_LOOP 4 ++#define WLC_SET_LOOP 5 ++#define WLC_DUMP 6 ++#define WLC_GET_MSGLEVEL 7 ++#define WLC_SET_MSGLEVEL 8 ++#define WLC_GET_PROMISC 9 ++#define WLC_SET_PROMISC 10 ++/* #define WLC_OVERLAY_IOCTL 11 */ /* not supported */ ++#define WLC_GET_RATE 12 ++#define WLC_GET_MAX_RATE 13 ++#define WLC_GET_INSTANCE 14 ++/* #define WLC_GET_FRAG 15 */ /* no longer supported */ ++/* #define WLC_SET_FRAG 16 */ /* no longer supported */ ++/* #define WLC_GET_RTS 17 */ /* no longer supported */ ++/* #define WLC_SET_RTS 18 */ /* no longer supported */ ++#define WLC_GET_INFRA 19 ++#define WLC_SET_INFRA 20 ++#define WLC_GET_AUTH 21 ++#define WLC_SET_AUTH 22 ++#define WLC_GET_BSSID 23 ++#define WLC_SET_BSSID 24 ++#define WLC_GET_SSID 25 ++#define WLC_SET_SSID 26 ++#define WLC_RESTART 27 ++#define WLC_TERMINATED 28 ++/* #define WLC_DUMP_SCB 28 */ /* no longer supported */ ++#define WLC_GET_CHANNEL 29 ++#define WLC_SET_CHANNEL 30 ++#define WLC_GET_SRL 31 ++#define WLC_SET_SRL 32 ++#define WLC_GET_LRL 33 ++#define WLC_SET_LRL 34 ++#define WLC_GET_PLCPHDR 35 ++#define WLC_SET_PLCPHDR 36 ++#define WLC_GET_RADIO 37 ++#define WLC_SET_RADIO 38 ++#define WLC_GET_PHYTYPE 39 ++#define WLC_DUMP_RATE 40 ++#define WLC_SET_RATE_PARAMS 41 ++#define WLC_GET_FIXRATE 42 ++#define WLC_SET_FIXRATE 43 ++/* #define WLC_GET_WEP 42 */ /* no longer supported */ ++/* #define WLC_SET_WEP 43 */ /* no longer supported */ ++#define WLC_GET_KEY 44 ++#define WLC_SET_KEY 45 ++#define WLC_GET_REGULATORY 46 ++#define WLC_SET_REGULATORY 47 ++#define WLC_GET_PASSIVE_SCAN 48 ++#define WLC_SET_PASSIVE_SCAN 49 ++#define WLC_SCAN 50 ++#define WLC_SCAN_RESULTS 51 ++#define WLC_DISASSOC 52 ++#define WLC_REASSOC 53 ++#define WLC_GET_ROAM_TRIGGER 54 ++#define WLC_SET_ROAM_TRIGGER 55 ++#define WLC_GET_ROAM_DELTA 56 ++#define WLC_SET_ROAM_DELTA 57 ++#define WLC_GET_ROAM_SCAN_PERIOD 58 ++#define WLC_SET_ROAM_SCAN_PERIOD 59 ++#define WLC_EVM 60 /* diag */ ++#define WLC_GET_TXANT 61 ++#define WLC_SET_TXANT 62 ++#define WLC_GET_ANTDIV 63 ++#define WLC_SET_ANTDIV 64 ++/* #define WLC_GET_TXPWR 65 */ /* no longer supported */ ++/* #define WLC_SET_TXPWR 66 */ /* no longer supported */ ++#define WLC_GET_CLOSED 67 ++#define WLC_SET_CLOSED 68 ++#define WLC_GET_MACLIST 69 ++#define WLC_SET_MACLIST 70 ++#define WLC_GET_RATESET 71 ++#define WLC_SET_RATESET 72 ++/* #define WLC_GET_LOCALE 73 */ /* no longer supported */ ++#define WLC_LONGTRAIN 74 ++#define WLC_GET_BCNPRD 75 ++#define WLC_SET_BCNPRD 76 ++#define WLC_GET_DTIMPRD 77 ++#define WLC_SET_DTIMPRD 78 ++#define WLC_GET_SROM 79 ++#define WLC_SET_SROM 80 ++#define WLC_GET_WEP_RESTRICT 81 ++#define WLC_SET_WEP_RESTRICT 82 ++#define WLC_GET_COUNTRY 83 ++#define WLC_SET_COUNTRY 84 ++#define WLC_GET_PM 85 ++#define WLC_SET_PM 86 ++#define WLC_GET_WAKE 87 ++#define WLC_SET_WAKE 88 ++/* #define WLC_GET_D11CNTS 89 */ /* -> "counters" iovar */ ++#define WLC_GET_FORCELINK 90 /* ndis only */ ++#define WLC_SET_FORCELINK 91 /* ndis only */ ++#define WLC_FREQ_ACCURACY 92 /* diag */ ++#define WLC_CARRIER_SUPPRESS 93 /* diag */ ++#define WLC_GET_PHYREG 94 ++#define WLC_SET_PHYREG 95 ++#define WLC_GET_RADIOREG 96 ++#define WLC_SET_RADIOREG 97 ++#define WLC_GET_REVINFO 98 ++#define WLC_GET_UCANTDIV 99 ++#define WLC_SET_UCANTDIV 100 ++#define WLC_R_REG 101 ++#define WLC_W_REG 102 ++/* #define WLC_DIAG_LOOPBACK 103 old tray diag */ ++/* #define WLC_RESET_D11CNTS 104 */ /* -> "reset_d11cnts" iovar */ ++#define WLC_GET_MACMODE 105 ++#define WLC_SET_MACMODE 106 ++#define WLC_GET_MONITOR 107 ++#define WLC_SET_MONITOR 108 ++#define WLC_GET_GMODE 109 ++#define WLC_SET_GMODE 110 ++#define WLC_GET_LEGACY_ERP 111 ++#define WLC_SET_LEGACY_ERP 112 ++#define WLC_GET_RX_ANT 113 ++#define WLC_GET_CURR_RATESET 114 /* current rateset */ ++#define WLC_GET_SCANSUPPRESS 115 ++#define WLC_SET_SCANSUPPRESS 116 ++#define WLC_GET_AP 117 ++#define WLC_SET_AP 118 ++#define WLC_GET_EAP_RESTRICT 119 ++#define WLC_SET_EAP_RESTRICT 120 ++#define WLC_SCB_AUTHORIZE 121 ++#define WLC_SCB_DEAUTHORIZE 122 ++#define WLC_GET_WDSLIST 123 ++#define WLC_SET_WDSLIST 124 ++#define WLC_GET_ATIM 125 ++#define WLC_SET_ATIM 126 ++#define WLC_GET_RSSI 127 ++#define WLC_GET_PHYANTDIV 128 ++#define WLC_SET_PHYANTDIV 129 ++#define WLC_AP_RX_ONLY 130 ++#define WLC_GET_TX_PATH_PWR 131 ++#define WLC_SET_TX_PATH_PWR 132 ++#define WLC_GET_WSEC 133 ++#define WLC_SET_WSEC 134 ++#define WLC_GET_PHY_NOISE 135 ++#define WLC_GET_BSS_INFO 136 ++#define WLC_GET_PKTCNTS 137 ++#define WLC_GET_LAZYWDS 138 ++#define WLC_SET_LAZYWDS 139 ++#define WLC_GET_BANDLIST 140 ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++#define WLC_GET_BAND 141 ++#define WLC_SET_BAND 142 ++#define WLC_SCB_DEAUTHENTICATE 143 ++#define WLC_GET_SHORTSLOT 144 ++#define WLC_GET_SHORTSLOT_OVERRIDE 145 ++#define WLC_SET_SHORTSLOT_OVERRIDE 146 ++#define WLC_GET_SHORTSLOT_RESTRICT 147 ++#define WLC_SET_SHORTSLOT_RESTRICT 148 ++#define WLC_GET_GMODE_PROTECTION 149 ++#define WLC_GET_GMODE_PROTECTION_OVERRIDE 150 ++#define WLC_SET_GMODE_PROTECTION_OVERRIDE 151 ++#define WLC_UPGRADE 152 ++/* #define WLC_GET_MRATE 153 */ /* no longer supported */ ++/* #define WLC_SET_MRATE 154 */ /* no longer supported */ ++#define WLC_GET_IGNORE_BCNS 155 ++#define WLC_SET_IGNORE_BCNS 156 ++#define WLC_GET_SCB_TIMEOUT 157 ++#define WLC_SET_SCB_TIMEOUT 158 ++#define WLC_GET_ASSOCLIST 159 ++#define WLC_GET_CLK 160 ++#define WLC_SET_CLK 161 ++#define WLC_GET_UP 162 ++#define WLC_OUT 163 ++#define WLC_GET_WPA_AUTH 164 ++#define WLC_SET_WPA_AUTH 165 ++#define WLC_GET_UCFLAGS 166 ++#define WLC_SET_UCFLAGS 167 ++#define WLC_GET_PWRIDX 168 ++#define WLC_SET_PWRIDX 169 ++#define WLC_GET_TSSI 170 ++#define WLC_GET_SUP_RATESET_OVERRIDE 171 ++#define WLC_SET_SUP_RATESET_OVERRIDE 172 ++/* #define WLC_SET_FAST_TIMER 173 */ /* no longer supported */ ++/* #define WLC_GET_FAST_TIMER 174 */ /* no longer supported */ ++/* #define WLC_SET_SLOW_TIMER 175 */ /* no longer supported */ ++/* #define WLC_GET_SLOW_TIMER 176 */ /* no longer supported */ ++/* #define WLC_DUMP_PHYREGS 177 */ /* no longer supported */ ++#define WLC_GET_PROTECTION_CONTROL 178 ++#define WLC_SET_PROTECTION_CONTROL 179 ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++#define WLC_GET_PHYLIST 180 ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++#define WLC_ENCRYPT_STRENGTH 181 /* ndis only */ ++#define WLC_DECRYPT_STATUS 182 /* ndis only */ ++#define WLC_GET_KEY_SEQ 183 ++#define WLC_GET_SCAN_CHANNEL_TIME 184 ++#define WLC_SET_SCAN_CHANNEL_TIME 185 ++#define WLC_GET_SCAN_UNASSOC_TIME 186 ++#define WLC_SET_SCAN_UNASSOC_TIME 187 ++#define WLC_GET_SCAN_HOME_TIME 188 ++#define WLC_SET_SCAN_HOME_TIME 189 ++#define WLC_GET_SCAN_NPROBES 190 ++#define WLC_SET_SCAN_NPROBES 191 ++#define WLC_GET_PRB_RESP_TIMEOUT 192 ++#define WLC_SET_PRB_RESP_TIMEOUT 193 ++#define WLC_GET_ATTEN 194 ++#define WLC_SET_ATTEN 195 ++#define WLC_GET_SHMEM 196 /* diag */ ++#define WLC_SET_SHMEM 197 /* diag */ ++/* #define WLC_GET_GMODE_PROTECTION_CTS 198 */ /* no longer supported */ ++/* #define WLC_SET_GMODE_PROTECTION_CTS 199 */ /* no longer supported */ ++#define WLC_SET_WSEC_TEST 200 ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++#define WLC_SCB_DEAUTHENTICATE_FOR_REASON 201 ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++#define WLC_TKIP_COUNTERMEASURES 202 ++#define WLC_GET_PIOMODE 203 ++#define WLC_SET_PIOMODE 204 ++#define WLC_SET_ASSOC_PREFER 205 ++#define WLC_GET_ASSOC_PREFER 206 ++#define WLC_SET_ROAM_PREFER 207 ++#define WLC_GET_ROAM_PREFER 208 ++#define WLC_SET_LED 209 ++#define WLC_GET_LED 210 ++#define WLC_GET_INTERFERENCE_MODE 211 ++#define WLC_SET_INTERFERENCE_MODE 212 ++#define WLC_GET_CHANNEL_QA 213 ++#define WLC_START_CHANNEL_QA 214 ++#define WLC_GET_CHANNEL_SEL 215 ++#define WLC_START_CHANNEL_SEL 216 ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++#define WLC_GET_VALID_CHANNELS 217 ++#define WLC_GET_FAKEFRAG 218 ++#define WLC_SET_FAKEFRAG 219 ++#define WLC_GET_PWROUT_PERCENTAGE 220 ++#define WLC_SET_PWROUT_PERCENTAGE 221 ++#define WLC_SET_BAD_FRAME_PREEMPT 222 ++#define WLC_GET_BAD_FRAME_PREEMPT 223 ++#define WLC_SET_LEAP_LIST 224 ++#define WLC_GET_LEAP_LIST 225 ++#define WLC_GET_CWMIN 226 ++#define WLC_SET_CWMIN 227 ++#define WLC_GET_CWMAX 228 ++#define WLC_SET_CWMAX 229 ++#define WLC_GET_WET 230 ++#define WLC_SET_WET 231 ++#define WLC_GET_PUB 232 ++/* #define WLC_SET_GLACIAL_TIMER 233 */ /* no longer supported */ ++/* #define WLC_GET_GLACIAL_TIMER 234 */ /* no longer supported */ ++#define WLC_GET_KEY_PRIMARY 235 ++#define WLC_SET_KEY_PRIMARY 236 ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++ ++/* #define WLC_DUMP_RADIOREGS 237 */ /* no longer supported */ ++#define WLC_GET_ACI_ARGS 238 ++#define WLC_SET_ACI_ARGS 239 ++#define WLC_UNSET_CALLBACK 240 ++#define WLC_SET_CALLBACK 241 ++#define WLC_GET_RADAR 242 ++#define WLC_SET_RADAR 243 ++#define WLC_SET_SPECT_MANAGMENT 244 ++#define WLC_GET_SPECT_MANAGMENT 245 ++#define WLC_WDS_GET_REMOTE_HWADDR 246 /* handled in wl_linux.c/wl_vx.c */ ++#define WLC_WDS_GET_WPA_SUP 247 ++#define WLC_SET_CS_SCAN_TIMER 248 ++#define WLC_GET_CS_SCAN_TIMER 249 ++#define WLC_MEASURE_REQUEST 250 ++#define WLC_INIT 251 ++#define WLC_SEND_QUIET 252 ++#define WLC_KEEPALIVE 253 ++#define WLC_SEND_PWR_CONSTRAINT 254 ++#define WLC_UPGRADE_STATUS 255 ++#define WLC_CURRENT_PWR 256 ++#define WLC_GET_SCAN_PASSIVE_TIME 257 ++#define WLC_SET_SCAN_PASSIVE_TIME 258 ++#define WLC_LEGACY_LINK_BEHAVIOR 259 ++#define WLC_GET_CHANNELS_IN_COUNTRY 260 ++#define WLC_GET_COUNTRY_LIST 261 ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++#define WLC_GET_VAR 262 /* get value of named variable */ ++#define WLC_SET_VAR 263 /* set named variable to value */ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++#define WLC_NVRAM_GET 264 /* deprecated */ ++#define WLC_NVRAM_SET 265 ++#define WLC_NVRAM_DUMP 266 ++#define WLC_REBOOT 267 ++#define WLC_SET_WSEC_PMK 268 ++#define WLC_GET_AUTH_MODE 269 ++#define WLC_SET_AUTH_MODE 270 ++#define WLC_GET_WAKEENTRY 271 ++#define WLC_SET_WAKEENTRY 272 ++#define WLC_NDCONFIG_ITEM 273 /* currently handled in wl_oid.c */ ++#define WLC_NVOTPW 274 ++#define WLC_OTPW 275 ++#define WLC_IOV_BLOCK_GET 276 ++#define WLC_IOV_MODULES_GET 277 ++#define WLC_SOFT_RESET 278 ++#define WLC_GET_ALLOW_MODE 279 ++#define WLC_SET_ALLOW_MODE 280 ++#define WLC_GET_DESIRED_BSSID 281 ++#define WLC_SET_DESIRED_BSSID 282 ++#define WLC_DISASSOC_MYAP 283 ++#define WLC_GET_NBANDS 284 /* for Dongle EXT_STA support */ ++#define WLC_GET_BANDSTATES 285 /* for Dongle EXT_STA support */ ++#define WLC_GET_WLC_BSS_INFO 286 /* for Dongle EXT_STA support */ ++#define WLC_GET_ASSOC_INFO 287 /* for Dongle EXT_STA support */ ++#define WLC_GET_OID_PHY 288 /* for Dongle EXT_STA support */ ++#define WLC_SET_OID_PHY 289 /* for Dongle EXT_STA support */ ++#define WLC_SET_ASSOC_TIME 290 /* for Dongle EXT_STA support */ ++#define WLC_GET_DESIRED_SSID 291 /* for Dongle EXT_STA support */ ++#define WLC_GET_CHANSPEC 292 /* for Dongle EXT_STA support */ ++#define WLC_GET_ASSOC_STATE 293 /* for Dongle EXT_STA support */ ++#define WLC_SET_PHY_STATE 294 /* for Dongle EXT_STA support */ ++#define WLC_GET_SCAN_PENDING 295 /* for Dongle EXT_STA support */ ++#define WLC_GET_SCANREQ_PENDING 296 /* for Dongle EXT_STA support */ ++#define WLC_GET_PREV_ROAM_REASON 297 /* for Dongle EXT_STA support */ ++#define WLC_SET_PREV_ROAM_REASON 298 /* for Dongle EXT_STA support */ ++#define WLC_GET_BANDSTATES_PI 299 /* for Dongle EXT_STA support */ ++#define WLC_GET_PHY_STATE 300 /* for Dongle EXT_STA support */ ++#define WLC_GET_BSS_WPA_RSN 301 /* for Dongle EXT_STA support */ ++#define WLC_GET_BSS_WPA2_RSN 302 /* for Dongle EXT_STA support */ ++#define WLC_GET_BSS_BCN_TS 303 /* for Dongle EXT_STA support */ ++#define WLC_GET_INT_DISASSOC 304 /* for Dongle EXT_STA support */ ++#define WLC_SET_NUM_PEERS 305 /* for Dongle EXT_STA support */ ++#define WLC_GET_NUM_BSS 306 /* for Dongle EXT_STA support */ ++#define WLC_PHY_SAMPLE_COLLECT 307 /* phy sample collect mode */ ++/* #define WLC_UM_PRIV 308 */ /* Deprecated: usermode driver */ ++#define WLC_GET_CMD 309 ++/* #define WLC_LAST 310 */ /* Never used - can be reused */ ++#define WLC_SET_INTERFERENCE_OVERRIDE_MODE 311 /* set inter mode override */ ++#define WLC_GET_INTERFERENCE_OVERRIDE_MODE 312 /* get inter mode override */ ++/* #define WLC_GET_WAI_RESTRICT 313 */ /* for WAPI, deprecated use iovar instead */ ++/* #define WLC_SET_WAI_RESTRICT 314 */ /* for WAPI, deprecated use iovar instead */ ++/* #define WLC_SET_WAI_REKEY 315 */ /* for WAPI, deprecated use iovar instead */ ++#define WLC_SET_NAT_CONFIG 316 /* for configuring NAT filter driver */ ++#define WLC_GET_NAT_STATE 317 ++#define WLC_LAST 318 ++ ++#ifndef EPICTRL_COOKIE ++#define EPICTRL_COOKIE 0xABADCEDE ++#endif ++ ++/* vx wlc ioctl's offset */ ++#define CMN_IOCTL_OFF 0x180 ++ ++/* ++ * custom OID support ++ * ++ * 0xFF - implementation specific OID ++ * 0xE4 - first byte of Broadcom PCI vendor ID ++ * 0x14 - second byte of Broadcom PCI vendor ID ++ * 0xXX - the custom OID number ++ */ ++ ++/* begin 0x1f values beyond the start of the ET driver range. */ ++#define WL_OID_BASE 0xFFE41420 ++ ++/* NDIS overrides */ ++#define OID_WL_GETINSTANCE (WL_OID_BASE + WLC_GET_INSTANCE) ++#define OID_WL_GET_FORCELINK (WL_OID_BASE + WLC_GET_FORCELINK) ++#define OID_WL_SET_FORCELINK (WL_OID_BASE + WLC_SET_FORCELINK) ++#define OID_WL_ENCRYPT_STRENGTH (WL_OID_BASE + WLC_ENCRYPT_STRENGTH) ++#define OID_WL_DECRYPT_STATUS (WL_OID_BASE + WLC_DECRYPT_STATUS) ++#define OID_LEGACY_LINK_BEHAVIOR (WL_OID_BASE + WLC_LEGACY_LINK_BEHAVIOR) ++#define OID_WL_NDCONFIG_ITEM (WL_OID_BASE + WLC_NDCONFIG_ITEM) ++ ++/* EXT_STA Dongle suuport */ ++#define OID_STA_CHANSPEC (WL_OID_BASE + WLC_GET_CHANSPEC) ++#define OID_STA_NBANDS (WL_OID_BASE + WLC_GET_NBANDS) ++#define OID_STA_GET_PHY (WL_OID_BASE + WLC_GET_OID_PHY) ++#define OID_STA_SET_PHY (WL_OID_BASE + WLC_SET_OID_PHY) ++#define OID_STA_ASSOC_TIME (WL_OID_BASE + WLC_SET_ASSOC_TIME) ++#define OID_STA_DESIRED_SSID (WL_OID_BASE + WLC_GET_DESIRED_SSID) ++#define OID_STA_SET_PHY_STATE (WL_OID_BASE + WLC_SET_PHY_STATE) ++#define OID_STA_SCAN_PENDING (WL_OID_BASE + WLC_GET_SCAN_PENDING) ++#define OID_STA_SCANREQ_PENDING (WL_OID_BASE + WLC_GET_SCANREQ_PENDING) ++#define OID_STA_GET_ROAM_REASON (WL_OID_BASE + WLC_GET_PREV_ROAM_REASON) ++#define OID_STA_SET_ROAM_REASON (WL_OID_BASE + WLC_SET_PREV_ROAM_REASON) ++#define OID_STA_GET_PHY_STATE (WL_OID_BASE + WLC_GET_PHY_STATE) ++#define OID_STA_INT_DISASSOC (WL_OID_BASE + WLC_GET_INT_DISASSOC) ++#define OID_STA_SET_NUM_PEERS (WL_OID_BASE + WLC_SET_NUM_PEERS) ++#define OID_STA_GET_NUM_BSS (WL_OID_BASE + WLC_GET_NUM_BSS) ++ ++/* NAT filter driver support */ ++#define OID_NAT_SET_CONFIG (WL_OID_BASE + WLC_SET_NAT_CONFIG) ++#define OID_NAT_GET_STATE (WL_OID_BASE + WLC_GET_NAT_STATE) ++ ++#define WL_DECRYPT_STATUS_SUCCESS 1 ++#define WL_DECRYPT_STATUS_FAILURE 2 ++#define WL_DECRYPT_STATUS_UNKNOWN 3 ++ ++/* allows user-mode app to poll the status of USB image upgrade */ ++#define WLC_UPGRADE_SUCCESS 0 ++#define WLC_UPGRADE_PENDING 1 ++ ++#ifdef CONFIG_USBRNDIS_RETAIL ++/* struct passed in for WLC_NDCONFIG_ITEM */ ++typedef struct { ++ char *name; ++ void *param; ++} ndconfig_item_t; ++#endif ++ ++ ++/* WLC_GET_AUTH, WLC_SET_AUTH values */ ++#define WL_AUTH_OPEN_SYSTEM 0 /* d11 open authentication */ ++#define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ ++#ifdef BCM4330_CHIP ++#define WL_AUTH_OPEN_SHARED 2 /* try open, then shared if open failed w/rc 13 */ ++#else ++/* BCM4334(Phoenex branch) value changed to 3 */ ++#define WL_AUTH_OPEN_SHARED 3 /* try open, then shared if open failed w/rc 13 */ ++#endif ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* Bit masks for radio disabled status - returned by WL_GET_RADIO */ ++#define WL_RADIO_SW_DISABLE (1<<0) ++#define WL_RADIO_HW_DISABLE (1<<1) ++#define WL_RADIO_MPC_DISABLE (1<<2) ++#define WL_RADIO_COUNTRY_DISABLE (1<<3) /* some countries don't support any channel */ ++ ++#define WL_SPURAVOID_OFF 0 ++#define WL_SPURAVOID_ON1 1 ++#define WL_SPURAVOID_ON2 2 ++ ++/* Override bit for WLC_SET_TXPWR. if set, ignore other level limits */ ++#define WL_TXPWR_OVERRIDE (1U<<31) ++#define WL_TXPWR_NEG (1U<<30) ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++#define WL_PHY_PAVARS_LEN 32 /* Phy type, Band range, chain, a1[0], b0[0], b1[0] ... */ ++ ++#define WL_PHY_PAVAR_VER 1 /* pavars version */ ++ ++typedef struct wl_po { ++ uint16 phy_type; /* Phy type */ ++ uint16 band; ++ uint16 cckpo; ++ uint32 ofdmpo; ++ uint16 mcspo[8]; ++} wl_po_t; ++ ++/* a large TX Power as an init value to factor out of MIN() calculations, ++ * keep low enough to fit in an int8, units are .25 dBm ++ */ ++#define WLC_TXPWR_MAX (127) /* ~32 dBm = 1,500 mW */ ++ ++/* "diag" iovar argument and error code */ ++#define WL_DIAG_INTERRUPT 1 /* d11 loopback interrupt test */ ++#define WL_DIAG_LOOPBACK 2 /* d11 loopback data test */ ++#define WL_DIAG_MEMORY 3 /* d11 memory test */ ++#define WL_DIAG_LED 4 /* LED test */ ++#define WL_DIAG_REG 5 /* d11/phy register test */ ++#define WL_DIAG_SROM 6 /* srom read/crc test */ ++#define WL_DIAG_DMA 7 /* DMA test */ ++#define WL_DIAG_LOOPBACK_EXT 8 /* enhenced d11 loopback data test */ ++ ++#define WL_DIAGERR_SUCCESS 0 ++#define WL_DIAGERR_FAIL_TO_RUN 1 /* unable to run requested diag */ ++#define WL_DIAGERR_NOT_SUPPORTED 2 /* diag requested is not supported */ ++#define WL_DIAGERR_INTERRUPT_FAIL 3 /* loopback interrupt test failed */ ++#define WL_DIAGERR_LOOPBACK_FAIL 4 /* loopback data test failed */ ++#define WL_DIAGERR_SROM_FAIL 5 /* srom read failed */ ++#define WL_DIAGERR_SROM_BADCRC 6 /* srom crc failed */ ++#define WL_DIAGERR_REG_FAIL 7 /* d11/phy register test failed */ ++#define WL_DIAGERR_MEMORY_FAIL 8 /* d11 memory test failed */ ++#define WL_DIAGERR_NOMEM 9 /* diag test failed due to no memory */ ++#define WL_DIAGERR_DMA_FAIL 10 /* DMA test failed */ ++ ++#define WL_DIAGERR_MEMORY_TIMEOUT 11 /* d11 memory test didn't finish in time */ ++#define WL_DIAGERR_MEMORY_BADPATTERN 12 /* d11 memory test result in bad pattern */ ++ ++/* band types */ ++#define WLC_BAND_AUTO 0 /* auto-select */ ++#define WLC_BAND_5G 1 /* 5 Ghz */ ++#define WLC_BAND_2G 2 /* 2.4 Ghz */ ++#define WLC_BAND_ALL 3 /* all bands */ ++ ++/* band range returned by band_range iovar */ ++#define WL_CHAN_FREQ_RANGE_2G 0 ++#define WL_CHAN_FREQ_RANGE_5GL 1 ++#define WL_CHAN_FREQ_RANGE_5GM 2 ++#define WL_CHAN_FREQ_RANGE_5GH 3 ++ ++#define WL_CHAN_FREQ_RANGE_5G_BAND0 1 ++#define WL_CHAN_FREQ_RANGE_5G_BAND1 2 ++#define WL_CHAN_FREQ_RANGE_5G_BAND2 3 ++#define WL_CHAN_FREQ_RANGE_5G_BAND3 4 ++ ++#define WL_CHAN_FREQ_RANGE_5G_4BAND 5 ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* phy types (returned by WLC_GET_PHYTPE) */ ++#define WLC_PHY_TYPE_A 0 ++#define WLC_PHY_TYPE_B 1 ++#define WLC_PHY_TYPE_G 2 ++#define WLC_PHY_TYPE_N 4 ++#define WLC_PHY_TYPE_LP 5 ++#define WLC_PHY_TYPE_SSN 6 ++#define WLC_PHY_TYPE_HT 7 ++#define WLC_PHY_TYPE_LCN 8 ++#define WLC_PHY_TYPE_LCN40 10 ++#define WLC_PHY_TYPE_AC 11 ++#define WLC_PHY_TYPE_NULL 0xf ++ ++/* Values for PM */ ++#define PM_OFF 0 ++#define PM_MAX 1 ++#define PM_FAST 2 ++#define PM_FORCE_OFF 3 /* use this bit to force PM off even bt is active */ ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++/* MAC list modes */ ++#define WLC_MACMODE_DISABLED 0 /* MAC list disabled */ ++#define WLC_MACMODE_DENY 1 /* Deny specified (i.e. allow unspecified) */ ++#define WLC_MACMODE_ALLOW 2 /* Allow specified (i.e. deny unspecified) */ ++ ++/* ++ * 54g modes (basic bits may still be overridden) ++ * ++ * GMODE_LEGACY_B Rateset: 1b, 2b, 5.5, 11 ++ * Preamble: Long ++ * Shortslot: Off ++ * GMODE_AUTO Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54 ++ * Extended Rateset: 6, 9, 12, 48 ++ * Preamble: Long ++ * Shortslot: Auto ++ * GMODE_ONLY Rateset: 1b, 2b, 5.5b, 11b, 18, 24b, 36, 54 ++ * Extended Rateset: 6b, 9, 12b, 48 ++ * Preamble: Short required ++ * Shortslot: Auto ++ * GMODE_B_DEFERRED Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54 ++ * Extended Rateset: 6, 9, 12, 48 ++ * Preamble: Long ++ * Shortslot: On ++ * GMODE_PERFORMANCE Rateset: 1b, 2b, 5.5b, 6b, 9, 11b, 12b, 18, 24b, 36, 48, 54 ++ * Preamble: Short required ++ * Shortslot: On and required ++ * GMODE_LRS Rateset: 1b, 2b, 5.5b, 11b ++ * Extended Rateset: 6, 9, 12, 18, 24, 36, 48, 54 ++ * Preamble: Long ++ * Shortslot: Auto ++ */ ++#define GMODE_LEGACY_B 0 ++#define GMODE_AUTO 1 ++#define GMODE_ONLY 2 ++#define GMODE_B_DEFERRED 3 ++#define GMODE_PERFORMANCE 4 ++#define GMODE_LRS 5 ++#define GMODE_MAX 6 ++ ++/* values for PLCPHdr_override */ ++#define WLC_PLCP_AUTO -1 ++#define WLC_PLCP_SHORT 0 ++#define WLC_PLCP_LONG 1 ++ ++/* values for g_protection_override and n_protection_override */ ++#define WLC_PROTECTION_AUTO -1 ++#define WLC_PROTECTION_OFF 0 ++#define WLC_PROTECTION_ON 1 ++#define WLC_PROTECTION_MMHDR_ONLY 2 ++#define WLC_PROTECTION_CTS_ONLY 3 ++ ++/* values for g_protection_control and n_protection_control */ ++#define WLC_PROTECTION_CTL_OFF 0 ++#define WLC_PROTECTION_CTL_LOCAL 1 ++#define WLC_PROTECTION_CTL_OVERLAP 2 ++ ++/* values for n_protection */ ++#define WLC_N_PROTECTION_OFF 0 ++#define WLC_N_PROTECTION_OPTIONAL 1 ++#define WLC_N_PROTECTION_20IN40 2 ++#define WLC_N_PROTECTION_MIXEDMODE 3 ++ ++/* values for n_preamble_type */ ++#define WLC_N_PREAMBLE_MIXEDMODE 0 ++#define WLC_N_PREAMBLE_GF 1 ++#define WLC_N_PREAMBLE_GF_BRCM 2 ++ ++/* values for band specific 40MHz capabilities (deprecated) */ ++#define WLC_N_BW_20ALL 0 ++#define WLC_N_BW_40ALL 1 ++#define WLC_N_BW_20IN2G_40IN5G 2 ++ ++#define WLC_BW_20MHZ_BIT (1<<0) ++#define WLC_BW_40MHZ_BIT (1<<1) ++#define WLC_BW_80MHZ_BIT (1<<2) ++ ++/* Bandwidth capabilities */ ++#define WLC_BW_CAP_20MHZ (WLC_BW_20MHZ_BIT) ++#define WLC_BW_CAP_40MHZ (WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) ++#define WLC_BW_CAP_80MHZ (WLC_BW_80MHZ_BIT|WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) ++#define WLC_BW_CAP_UNRESTRICTED 0xFF ++ ++#define WL_BW_CAP_20MHZ(bw_cap) (((bw_cap) & WLC_BW_20MHZ_BIT) ? TRUE : FALSE) ++#define WL_BW_CAP_40MHZ(bw_cap) (((bw_cap) & WLC_BW_40MHZ_BIT) ? TRUE : FALSE) ++#define WL_BW_CAP_80MHZ(bw_cap) (((bw_cap) & WLC_BW_80MHZ_BIT) ? TRUE : FALSE) ++ ++/* values to force tx/rx chain */ ++#define WLC_N_TXRX_CHAIN0 0 ++#define WLC_N_TXRX_CHAIN1 1 ++ ++/* bitflags for SGI support (sgi_rx iovar) */ ++#define WLC_N_SGI_20 0x01 ++#define WLC_N_SGI_40 0x02 ++#define WLC_VHT_SGI_80 0x04 ++ ++/* when sgi_tx==WLC_SGI_ALL, bypass rate selection, enable sgi for all mcs */ ++#define WLC_SGI_ALL 0x02 ++ ++#define LISTEN_INTERVAL 10 ++/* interference mitigation options */ ++#define INTERFERE_OVRRIDE_OFF -1 /* interference override off */ ++#define INTERFERE_NONE 0 /* off */ ++#define NON_WLAN 1 /* foreign/non 802.11 interference, no auto detect */ ++#define WLAN_MANUAL 2 /* ACI: no auto detection */ ++#define WLAN_AUTO 3 /* ACI: auto detect */ ++#define WLAN_AUTO_W_NOISE 4 /* ACI: auto - detect and non 802.11 interference */ ++#define AUTO_ACTIVE (1 << 7) /* Auto is currently active */ ++ ++/* AP environment */ ++#define AP_ENV_DETECT_NOT_USED 0 /* We aren't using AP environment detection */ ++#define AP_ENV_DENSE 1 /* "Corporate" or other AP dense environment */ ++#define AP_ENV_SPARSE 2 /* "Home" or other sparse environment */ ++#define AP_ENV_INDETERMINATE 3 /* AP environment hasn't been identified */ ++ ++typedef struct wl_aci_args { ++ int enter_aci_thresh; /* Trigger level to start detecting ACI */ ++ int exit_aci_thresh; /* Trigger level to exit ACI mode */ ++ int usec_spin; /* microsecs to delay between rssi samples */ ++ int glitch_delay; /* interval between ACI scans when glitch count is consistently high */ ++ uint16 nphy_adcpwr_enter_thresh; /* ADC power to enter ACI mitigation mode */ ++ uint16 nphy_adcpwr_exit_thresh; /* ADC power to exit ACI mitigation mode */ ++ uint16 nphy_repeat_ctr; /* Number of tries per channel to compute power */ ++ uint16 nphy_num_samples; /* Number of samples to compute power on one channel */ ++ uint16 nphy_undetect_window_sz; /* num of undetects to exit ACI Mitigation mode */ ++ uint16 nphy_b_energy_lo_aci; /* low ACI power energy threshold for bphy */ ++ uint16 nphy_b_energy_md_aci; /* mid ACI power energy threshold for bphy */ ++ uint16 nphy_b_energy_hi_aci; /* high ACI power energy threshold for bphy */ ++ uint16 nphy_noise_noassoc_glitch_th_up; /* wl interference 4 */ ++ uint16 nphy_noise_noassoc_glitch_th_dn; ++ uint16 nphy_noise_assoc_glitch_th_up; ++ uint16 nphy_noise_assoc_glitch_th_dn; ++ uint16 nphy_noise_assoc_aci_glitch_th_up; ++ uint16 nphy_noise_assoc_aci_glitch_th_dn; ++ uint16 nphy_noise_assoc_enter_th; ++ uint16 nphy_noise_noassoc_enter_th; ++ uint16 nphy_noise_assoc_rx_glitch_badplcp_enter_th; ++ uint16 nphy_noise_noassoc_crsidx_incr; ++ uint16 nphy_noise_assoc_crsidx_incr; ++ uint16 nphy_noise_crsidx_decr; ++} wl_aci_args_t; ++ ++#define TRIGGER_NOW 0 ++#define TRIGGER_CRS 0x01 ++#define TRIGGER_CRSDEASSERT 0x02 ++#define TRIGGER_GOODFCS 0x04 ++#define TRIGGER_BADFCS 0x08 ++#define TRIGGER_BADPLCP 0x10 ++#define TRIGGER_CRSGLITCH 0x20 ++#define WL_ACI_ARGS_LEGACY_LENGTH 16 /* bytes of pre NPHY aci args */ ++#define WL_SAMPLECOLLECT_T_VERSION 2 /* version of wl_samplecollect_args_t struct */ ++typedef struct wl_samplecollect_args { ++ /* version 0 fields */ ++ uint8 coll_us; ++ int cores; ++ /* add'l version 1 fields */ ++ uint16 version; /* see definition of WL_SAMPLECOLLECT_T_VERSION */ ++ uint16 length; /* length of entire structure */ ++ int8 trigger; ++ uint16 timeout; ++ uint16 mode; ++ uint32 pre_dur; ++ uint32 post_dur; ++ uint8 gpio_sel; ++ bool downsamp; ++ bool be_deaf; ++ bool agc; /* loop from init gain and going down */ ++ bool filter; /* override high pass corners to lowest */ ++ /* add'l version 2 fields */ ++ uint8 trigger_state; ++ uint8 module_sel1; ++ uint8 module_sel2; ++ uint16 nsamps; ++} wl_samplecollect_args_t; ++ ++#define WL_SAMPLEDATA_HEADER_TYPE 1 ++#define WL_SAMPLEDATA_HEADER_SIZE 80 /* sample collect header size (bytes) */ ++#define WL_SAMPLEDATA_TYPE 2 ++#define WL_SAMPLEDATA_SEQ 0xff /* sequence # */ ++#define WL_SAMPLEDATA_MORE_DATA 0x100 /* more data mask */ ++#define WL_SAMPLEDATA_T_VERSION 1 /* version of wl_samplecollect_args_t struct */ ++/* version for unpacked sample data, int16 {(I,Q),Core(0..N)} */ ++#define WL_SAMPLEDATA_T_VERSION_SPEC_AN 2 ++ ++typedef struct wl_sampledata { ++ uint16 version; /* structure version */ ++ uint16 size; /* size of structure */ ++ uint16 tag; /* Header/Data */ ++ uint16 length; /* data length */ ++ uint32 flag; /* bit def */ ++} wl_sampledata_t; ++ ++/* wl_radar_args_t */ ++typedef struct { ++ int npulses; /* required number of pulses at n * t_int */ ++ int ncontig; /* required number of pulses at t_int */ ++ int min_pw; /* minimum pulse width (20 MHz clocks) */ ++ int max_pw; /* maximum pulse width (20 MHz clocks) */ ++ uint16 thresh0; /* Radar detection, thresh 0 */ ++ uint16 thresh1; /* Radar detection, thresh 1 */ ++ uint16 blank; /* Radar detection, blank control */ ++ uint16 fmdemodcfg; /* Radar detection, fmdemod config */ ++ int npulses_lp; /* Radar detection, minimum long pulses */ ++ int min_pw_lp; /* Minimum pulsewidth for long pulses */ ++ int max_pw_lp; /* Maximum pulsewidth for long pulses */ ++ int min_fm_lp; /* Minimum fm for long pulses */ ++ int max_span_lp; /* Maximum deltat for long pulses */ ++ int min_deltat; /* Minimum spacing between pulses */ ++ int max_deltat; /* Maximum spacing between pulses */ ++ uint16 autocorr; /* Radar detection, autocorr on or off */ ++ uint16 st_level_time; /* Radar detection, start_timing level */ ++ uint16 t2_min; /* minimum clocks needed to remain in state 2 */ ++ uint32 version; /* version */ ++ uint32 fra_pulse_err; /* sample error margin for detecting French radar pulsed */ ++ int npulses_fra; /* Radar detection, minimum French pulses set */ ++ int npulses_stg2; /* Radar detection, minimum staggered-2 pulses set */ ++ int npulses_stg3; /* Radar detection, minimum staggered-3 pulses set */ ++ uint16 percal_mask; /* defines which period cal is masked from radar detection */ ++ int quant; /* quantization resolution to pulse positions */ ++ uint32 min_burst_intv_lp; /* minimum burst to burst interval for bin3 radar */ ++ uint32 max_burst_intv_lp; /* maximum burst to burst interval for bin3 radar */ ++ int nskip_rst_lp; /* number of skipped pulses before resetting lp buffer */ ++ int max_pw_tol; /* maximum tollerance allowed in detected pulse width for radar detection */ ++ uint16 feature_mask; /* 16-bit mask to specify enabled features */ ++} wl_radar_args_t; ++ ++#define WL_RADAR_ARGS_VERSION 2 ++ ++typedef struct { ++ uint32 version; /* version */ ++ uint16 thresh0_20_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 20MHz */ ++ uint16 thresh1_20_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 20MHz */ ++ uint16 thresh0_40_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 40MHz */ ++ uint16 thresh1_40_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 40MHz */ ++ uint16 thresh0_80_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 80MHz */ ++ uint16 thresh1_80_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 80MHz */ ++ uint16 thresh0_160_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 160MHz */ ++ uint16 thresh1_160_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 160MHz */ ++ uint16 thresh0_20_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 20MHz */ ++ uint16 thresh1_20_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 20MHz */ ++ uint16 thresh0_40_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 40MHz */ ++ uint16 thresh1_40_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 40MHz */ ++ uint16 thresh0_80_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 80MHz */ ++ uint16 thresh1_80_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 80MHz */ ++ uint16 thresh0_160_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 160MHz */ ++ uint16 thresh1_160_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 160MHz */ ++} wl_radar_thr_t; ++ ++#define WL_RADAR_THR_VERSION 2 ++#define WL_THRESHOLD_LO_BAND 70 /* range from 5250MHz - 5350MHz */ ++ ++/* radar iovar SET defines */ ++#define WL_RADAR_DETECTOR_OFF 0 /* radar detector off */ ++#define WL_RADAR_DETECTOR_ON 1 /* radar detector on */ ++#define WL_RADAR_SIMULATED 2 /* force radar detector to declare ++ * detection once ++ */ ++#define WL_RSSI_ANT_VERSION 1 /* current version of wl_rssi_ant_t */ ++#define WL_ANT_RX_MAX 2 /* max 2 receive antennas */ ++#define WL_ANT_HT_RX_MAX 3 /* max 3 receive antennas/cores */ ++#define WL_ANT_IDX_1 0 /* antenna index 1 */ ++#define WL_ANT_IDX_2 1 /* antenna index 2 */ ++ ++#ifndef WL_RSSI_ANT_MAX ++#define WL_RSSI_ANT_MAX 4 /* max possible rx antennas */ ++#elif WL_RSSI_ANT_MAX != 4 ++#error "WL_RSSI_ANT_MAX does not match" ++#endif ++ ++/* RSSI per antenna */ ++typedef struct { ++ uint32 version; /* version field */ ++ uint32 count; /* number of valid antenna rssi */ ++ int8 rssi_ant[WL_RSSI_ANT_MAX]; /* rssi per antenna */ ++} wl_rssi_ant_t; ++ ++/* dfs_status iovar-related defines */ ++ ++/* cac - channel availability check, ++ * ism - in-service monitoring ++ * csa - channel switching announcement ++ */ ++ ++/* cac state values */ ++#define WL_DFS_CACSTATE_IDLE 0 /* state for operating in non-radar channel */ ++#define WL_DFS_CACSTATE_PREISM_CAC 1 /* CAC in progress */ ++#define WL_DFS_CACSTATE_ISM 2 /* ISM in progress */ ++#define WL_DFS_CACSTATE_CSA 3 /* csa */ ++#define WL_DFS_CACSTATE_POSTISM_CAC 4 /* ISM CAC */ ++#define WL_DFS_CACSTATE_PREISM_OOC 5 /* PREISM OOC */ ++#define WL_DFS_CACSTATE_POSTISM_OOC 6 /* POSTISM OOC */ ++#define WL_DFS_CACSTATES 7 /* this many states exist */ ++ ++/* data structure used in 'dfs_status' wl interface, which is used to query dfs status */ ++typedef struct { ++ uint state; /* noted by WL_DFS_CACSTATE_XX. */ ++ uint duration; /* time spent in ms in state. */ ++ /* as dfs enters ISM state, it removes the operational channel from quiet channel ++ * list and notes the channel in channel_cleared. set to 0 if no channel is cleared ++ */ ++ chanspec_t chanspec_cleared; ++ /* chanspec cleared used to be a uint, add another to uint16 to maintain size */ ++ uint16 pad; ++} wl_dfs_status_t; ++ ++#define NUM_PWRCTRL_RATES 12 ++ ++typedef struct { ++ uint8 txpwr_band_max[NUM_PWRCTRL_RATES]; /* User set target */ ++ uint8 txpwr_limit[NUM_PWRCTRL_RATES]; /* reg and local power limit */ ++ uint8 txpwr_local_max; /* local max according to the AP */ ++ uint8 txpwr_local_constraint; /* local constraint according to the AP */ ++ uint8 txpwr_chan_reg_max; /* Regulatory max for this channel */ ++ uint8 txpwr_target[2][NUM_PWRCTRL_RATES]; /* Latest target for 2.4 and 5 Ghz */ ++ uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ ++ uint8 txpwr_opo[NUM_PWRCTRL_RATES]; /* On G phy, OFDM power offset */ ++ uint8 txpwr_bphy_cck_max[NUM_PWRCTRL_RATES]; /* Max CCK power for this band (SROM) */ ++ uint8 txpwr_bphy_ofdm_max; /* Max OFDM power for this band (SROM) */ ++ uint8 txpwr_aphy_max[NUM_PWRCTRL_RATES]; /* Max power for A band (SROM) */ ++ int8 txpwr_antgain[2]; /* Ant gain for each band - from SROM */ ++ uint8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ ++} tx_power_legacy_t; ++ ++#define WL_TX_POWER_RATES_LEGACY 45 ++#define WL_TX_POWER_MCS20_FIRST 12 ++#define WL_TX_POWER_MCS20_NUM 16 ++#define WL_TX_POWER_MCS40_FIRST 28 ++#define WL_TX_POWER_MCS40_NUM 17 ++ ++typedef struct { ++ uint32 flags; ++ chanspec_t chanspec; /* txpwr report for this channel */ ++ chanspec_t local_chanspec; /* channel on which we are associated */ ++ uint8 local_max; /* local max according to the AP */ ++ uint8 local_constraint; /* local constraint according to the AP */ ++ int8 antgain[2]; /* Ant gain for each band - from SROM */ ++ uint8 rf_cores; /* count of RF Cores being reported */ ++ uint8 est_Pout[4]; /* Latest tx power out estimate per RF ++ * chain without adjustment ++ */ ++ uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ ++ uint8 user_limit[WL_TX_POWER_RATES_LEGACY]; /* User limit */ ++ uint8 reg_limit[WL_TX_POWER_RATES_LEGACY]; /* Regulatory power limit */ ++ uint8 board_limit[WL_TX_POWER_RATES_LEGACY]; /* Max power board can support (SROM) */ ++ uint8 target[WL_TX_POWER_RATES_LEGACY]; /* Latest target power */ ++} tx_power_legacy2_t; ++ ++/* TX Power index defines */ ++#define WL_NUM_RATES_CCK 4 /* 1, 2, 5.5, 11 Mbps */ ++#define WL_NUM_RATES_OFDM 8 /* 6, 9, 12, 18, 24, 36, 48, 54 Mbps SISO/CDD */ ++#define WL_NUM_RATES_MCS_1STREAM 8 /* MCS 0-7 1-stream rates - SISO/CDD/STBC/MCS */ ++#define WL_NUM_RATES_EXTRA_VHT 2 /* Additional VHT 11AC rates */ ++#define WL_NUM_RATES_VHT 10 ++#define WL_NUM_RATES_MCS32 1 ++ ++#define WLC_NUM_RATES_CCK WL_NUM_RATES_CCK ++#define WLC_NUM_RATES_OFDM WL_NUM_RATES_OFDM ++#define WLC_NUM_RATES_MCS_1_STREAM WL_NUM_RATES_MCS_1STREAM ++#define WLC_NUM_RATES_MCS_2_STREAM WL_NUM_RATES_MCS_1STREAM ++#define WLC_NUM_RATES_MCS32 WL_NUM_RATES_MCS32 ++#define WL_TX_POWER_CCK_NUM WL_NUM_RATES_CCK ++#define WL_TX_POWER_OFDM_NUM WL_NUM_RATES_OFDM ++#define WL_TX_POWER_MCS_1_STREAM_NUM WL_NUM_RATES_MCS_1STREAM ++#define WL_TX_POWER_MCS_2_STREAM_NUM WL_NUM_RATES_MCS_1STREAM ++#define WL_TX_POWER_MCS_32_NUM WL_NUM_RATES_MCS32 ++ ++#define WL_NUM_2x2_ELEMENTS 4 ++#define WL_NUM_3x3_ELEMENTS 6 ++ ++typedef struct txppr { ++ /* start of 20MHz tx power limits */ ++ uint8 b20_1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ ++ uint8 b20_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ ++ ++ uint8 b20_1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b20_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ ++ uint8 b20_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b20_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ ++ ++ uint8 b20_1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b20_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ ++ uint8 b20_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b20_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ ++ uint8 b20_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ ++ ++ uint8 b20_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ ++ uint8 b20_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ ++ uint8 b20_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ ++ uint8 b20_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ ++ uint8 b20_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ ++ uint8 b20_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ ++ uint8 b20_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ ++ uint8 b20_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ ++ ++ /* start of 40MHz tx power limits */ ++ uint8 b40_dummy1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b40_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ ++ uint8 b40_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ ++ ++ uint8 b40_dummy1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b40_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b40_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ ++ uint8 b40_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b40_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ ++ ++ uint8 b40_dummy1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b40_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b40_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ ++ uint8 b40_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b40_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ ++ uint8 b40_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ ++ ++ uint8 b40_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ ++ uint8 b40_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ ++ uint8 b40_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ ++ uint8 b40_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ ++ uint8 b40_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ ++ uint8 b40_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ ++ uint8 b40_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ ++ uint8 b40_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ ++ ++ /* start of 20in40MHz tx power limits */ ++ uint8 b20in40_1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20in40_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ ++ uint8 b20in40_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ ++ ++ uint8 b20in40_1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20in40_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b20in40_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ ++ uint8 b20in40_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b20in40_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ ++ ++ uint8 b20in40_1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20in40_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* 20 in 40 MHz Legacy OFDM CDD */ ++ uint8 b20in40_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ ++ uint8 b20in40_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b20in40_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ ++ uint8 b20in40_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ ++ ++ uint8 b20in40_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ ++ uint8 b20in40_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ ++ uint8 b20in40_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ ++ uint8 b20in40_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ ++ uint8 b20in40_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ ++ uint8 b20in40_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ ++ uint8 b20in40_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ ++ uint8 b20in40_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ ++ ++ /* start of 80MHz tx power limits */ ++ uint8 b80_dummy1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b80_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ ++ uint8 b80_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ ++ ++ uint8 b80_dummy1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b80_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b80_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ ++ uint8 b80_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b80_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ ++ ++ uint8 b80_dummy1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b80_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b80_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ ++ uint8 b80_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b80_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ ++ uint8 b80_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ ++ ++ uint8 b80_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ ++ uint8 b80_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ ++ uint8 b80_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ ++ uint8 b80_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ ++ uint8 b80_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ ++ uint8 b80_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ ++ uint8 b80_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ ++ uint8 b80_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ ++ ++ /* start of 20in80MHz tx power limits */ ++ uint8 b20in80_1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20in80_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ ++ uint8 b20in80_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ ++ ++ uint8 b20in80_1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20in80_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b20in80_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ ++ uint8 b20in80_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b20in80_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ ++ ++ uint8 b20in80_1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b20in80_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b20in80_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ ++ uint8 b20in80_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b20in80_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ ++ uint8 b20in80_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ ++ ++ uint8 b20in80_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ ++ uint8 b20in80_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ ++ uint8 b20in80_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ ++ uint8 b20in80_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ ++ uint8 b20in80_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ ++ uint8 b20in80_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ ++ uint8 b20in80_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ ++ uint8 b20in80_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ ++ ++ /* start of 40in80MHz tx power limits */ ++ uint8 b40in80_dummy1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b40in80_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ ++ uint8 b40in80_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ ++ ++ uint8 b40in80_dummy1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b40in80_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ ++ uint8 b40in80_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ ++ uint8 b40in80_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b40in80_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ ++ ++ uint8 b40in80_dummy1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ ++ uint8 b40in80_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* MHz Legacy OFDM CDD */ ++ uint8 b40in80_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ ++ uint8 b40in80_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ ++ uint8 b40in80_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ ++ uint8 b40in80_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ ++ ++ uint8 b40in80_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ ++ uint8 b40in80_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ ++ uint8 b40in80_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ ++ uint8 b40in80_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ ++ uint8 b40in80_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ ++ uint8 b40in80_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ ++ uint8 b40in80_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ ++ uint8 b40in80_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ ++ ++ uint8 mcs32; /* C_CHECK - THIS NEEDS TO BE REMOVED THROUGHOUT THE CODE */ ++} txppr_t; ++ ++/* 20MHz */ ++#define WL_TX_POWER_CCK_FIRST OFFSETOF(txppr_t, b20_1x1dsss) ++#define WL_TX_POWER_OFDM20_FIRST OFFSETOF(txppr_t, b20_1x1ofdm) ++#define WL_TX_POWER_MCS20_SISO_FIRST OFFSETOF(txppr_t, b20_1x1mcs0) ++#define WL_TX_POWER_20_S1x1_FIRST OFFSETOF(txppr_t, b20_1x1mcs0) ++ ++#define WL_TX_POWER_CCK_CDD_S1x2_FIRST OFFSETOF(txppr_t, b20_1x2dsss) ++#define WL_TX_POWER_OFDM20_CDD_FIRST OFFSETOF(txppr_t, b20_1x2cdd_ofdm) ++#define WL_TX_POWER_MCS20_CDD_FIRST OFFSETOF(txppr_t, b20_1x2cdd_mcs0) ++#define WL_TX_POWER_20_S1x2_FIRST OFFSETOF(txppr_t, b20_1x2cdd_mcs0) ++#define WL_TX_POWER_MCS20_STBC_FIRST OFFSETOF(txppr_t, b20_2x2stbc_mcs0) ++#define WL_TX_POWER_MCS20_SDM_FIRST OFFSETOF(txppr_t, b20_2x2sdm_mcs8) ++#define WL_TX_POWER_20_S2x2_FIRST OFFSETOF(txppr_t, b20_2x2sdm_mcs8) ++ ++#define WL_TX_POWER_CCK_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20_1x3dsss) ++#define WL_TX_POWER_OFDM20_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20_1x3cdd_ofdm) ++#define WL_TX_POWER_20_S1x3_FIRST OFFSETOF(txppr_t, b20_1x3cdd_mcs0) ++#define WL_TX_POWER_20_STBC_S2x3_FIRST OFFSETOF(txppr_t, b20_2x3stbc_mcs0) ++#define WL_TX_POWER_20_S2x3_FIRST OFFSETOF(txppr_t, b20_2x3sdm_mcs8) ++#define WL_TX_POWER_20_S3x3_FIRST OFFSETOF(txppr_t, b20_3x3sdm_mcs16) ++ ++#define WL_TX_POWER_20_S1X1_VHT OFFSETOF(txppr_t, b20_1x1vht) ++#define WL_TX_POWER_20_S1X2_CDD_VHT OFFSETOF(txppr_t, b20_1x2cdd_vht) ++#define WL_TX_POWER_20_S2X2_STBC_VHT OFFSETOF(txppr_t, b20_2x2stbc_vht) ++#define WL_TX_POWER_20_S2X2_VHT OFFSETOF(txppr_t, b20_2x2sdm_vht) ++#define WL_TX_POWER_20_S1X3_CDD_VHT OFFSETOF(txppr_t, b20_1x3cdd_vht) ++#define WL_TX_POWER_20_S2X3_STBC_VHT OFFSETOF(txppr_t, b20_2x3stbc_vht) ++#define WL_TX_POWER_20_S2X3_VHT OFFSETOF(txppr_t, b20_2x3sdm_vht) ++#define WL_TX_POWER_20_S3X3_VHT OFFSETOF(txppr_t, b20_3x3sdm_vht) ++ ++/* 40MHz */ ++#define WL_TX_POWER_40_DUMMY_CCK_FIRST OFFSETOF(txppr_t, b40_dummy1x1dsss) ++#define WL_TX_POWER_OFDM40_FIRST OFFSETOF(txppr_t, b40_1x1ofdm) ++#define WL_TX_POWER_MCS40_SISO_FIRST OFFSETOF(txppr_t, b40_1x1mcs0) ++#define WL_TX_POWER_40_S1x1_FIRST OFFSETOF(txppr_t, b40_1x1mcs0) ++ ++#define WL_TX_POWER_40_DUMMY_CCK_CDD_S1x2_FIRST OFFSETOF(txppr_t, b40_dummy1x2dsss) ++#define WL_TX_POWER_OFDM40_CDD_FIRST OFFSETOF(txppr_t, b40_1x2cdd_ofdm) ++#define WL_TX_POWER_MCS40_CDD_FIRST OFFSETOF(txppr_t, b40_1x2cdd_mcs0) ++#define WL_TX_POWER_40_S1x2_FIRST OFFSETOF(txppr_t, b40_1x2cdd_mcs0) ++#define WL_TX_POWER_MCS40_STBC_FIRST OFFSETOF(txppr_t, b40_2x2stbc_mcs0) ++#define WL_TX_POWER_MCS40_SDM_FIRST OFFSETOF(txppr_t, b40_2x2sdm_mcs8) ++#define WL_TX_POWER_40_S2x2_FIRST OFFSETOF(txppr_t, b40_2x2sdm_mcs8) ++ ++#define WL_TX_POWER_40_DUMMY_CCK_CDD_S1x3_FIRST OFFSETOF(txppr_t, b40_dummy1x3dsss) ++#define WL_TX_POWER_OFDM40_CDD_S1x3_FIRST OFFSETOF(txppr_t, b40_1x3cdd_ofdm) ++#define WL_TX_POWER_40_S1x3_FIRST OFFSETOF(txppr_t, b40_1x3cdd_mcs0) ++#define WL_TX_POWER_40_STBC_S2x3_FIRST OFFSETOF(txppr_t, b40_2x3stbc_mcs0) ++#define WL_TX_POWER_40_S2x3_FIRST OFFSETOF(txppr_t, b40_2x3sdm_mcs8) ++#define WL_TX_POWER_40_S3x3_FIRST OFFSETOF(txppr_t, b40_3x3sdm_mcs16) ++ ++#define WL_TX_POWER_40_S1X1_VHT OFFSETOF(txppr_t, b40_1x1vht) ++#define WL_TX_POWER_40_S1X2_CDD_VHT OFFSETOF(txppr_t, b40_1x2cdd_vht) ++#define WL_TX_POWER_40_S2X2_STBC_VHT OFFSETOF(txppr_t, b40_2x2stbc_vht) ++#define WL_TX_POWER_40_S2X2_VHT OFFSETOF(txppr_t, b40_2x2sdm_vht) ++#define WL_TX_POWER_40_S1X3_CDD_VHT OFFSETOF(txppr_t, b40_1x3cdd_vht) ++#define WL_TX_POWER_40_S2X3_STBC_VHT OFFSETOF(txppr_t, b40_2x3stbc_vht) ++#define WL_TX_POWER_40_S2X3_VHT OFFSETOF(txppr_t, b40_2x3sdm_vht) ++#define WL_TX_POWER_40_S3X3_VHT OFFSETOF(txppr_t, b40_3x3sdm_vht) ++ ++/* 20 in 40MHz */ ++#define WL_TX_POWER_20UL_CCK_FIRST OFFSETOF(txppr_t, b20in40_1x1dsss) ++#define WL_TX_POWER_20UL_OFDM_FIRST OFFSETOF(txppr_t, b20in40_1x1ofdm) ++#define WL_TX_POWER_20UL_S1x1_FIRST OFFSETOF(txppr_t, b20in40_1x1mcs0) ++ ++#define WL_TX_POWER_CCK_20U_CDD_S1x2_FIRST OFFSETOF(txppr_t, b20in40_1x2dsss) ++#define WL_TX_POWER_20UL_OFDM_CDD_FIRST OFFSETOF(txppr_t, b20in40_1x2cdd_ofdm) ++#define WL_TX_POWER_20UL_S1x2_FIRST OFFSETOF(txppr_t, b20in40_1x2cdd_mcs0) ++#define WL_TX_POWER_20UL_STBC_S2x2_FIRST OFFSETOF(txppr_t, b20in40_2x2stbc_mcs0) ++#define WL_TX_POWER_20UL_S2x2_FIRST OFFSETOF(txppr_t, b20in40_2x2sdm_mcs8) ++ ++#define WL_TX_POWER_CCK_20U_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20in40_1x3dsss) ++#define WL_TX_POWER_20UL_OFDM_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20in40_1x3cdd_ofdm) ++#define WL_TX_POWER_20UL_S1x3_FIRST OFFSETOF(txppr_t, b20in40_1x3cdd_mcs0) ++#define WL_TX_POWER_20UL_STBC_S2x3_FIRST OFFSETOF(txppr_t, b20in40_2x3stbc_mcs0) ++#define WL_TX_POWER_20UL_S2x3_FIRST OFFSETOF(txppr_t, b20in40_2x3sdm_mcs8) ++#define WL_TX_POWER_20UL_S3x3_FIRST OFFSETOF(txppr_t, b20in40_3x3sdm_mcs16) ++ ++#define WL_TX_POWER_20UL_S1X1_VHT OFFSETOF(txppr_t, b20in40_1x1vht) ++#define WL_TX_POWER_20UL_S1X2_CDD_VHT OFFSETOF(txppr_t, b20in40_1x2cdd_vht) ++#define WL_TX_POWER_20UL_S2X2_STBC_VHT OFFSETOF(txppr_t, b20in40_2x2stbc_vht) ++#define WL_TX_POWER_20UL_S2X2_VHT OFFSETOF(txppr_t, b20in40_2x2sdm_vht) ++#define WL_TX_POWER_20UL_S1X3_CDD_VHT OFFSETOF(txppr_t, b20in40_1x3cdd_vht) ++#define WL_TX_POWER_20UL_S2X3_STBC_VHT OFFSETOF(txppr_t, b20in40_2x3stbc_vht) ++#define WL_TX_POWER_20UL_S2X3_VHT OFFSETOF(txppr_t, b20in40_2x3sdm_vht) ++#define WL_TX_POWER_20UL_S3X3_VHT OFFSETOF(txppr_t, b20in40_3x3sdm_vht) ++ ++/* 80MHz */ ++#define WL_TX_POWER_80_DUMMY_CCK_FIRST OFFSETOF(txppr_t, b80_dummy1x1dsss) ++#define WL_TX_POWER_OFDM80_FIRST OFFSETOF(txppr_t, b80_1x1ofdm) ++#define WL_TX_POWER_MCS80_SISO_FIRST OFFSETOF(txppr_t, b80_1x1mcs0) ++#define WL_TX_POWER_80_S1x1_FIRST OFFSETOF(txppr_t, b80_1x1mcs0) ++ ++#define WL_TX_POWER_80_DUMMY_CCK_CDD_S1x2_FIRST OFFSETOF(txppr_t, b80_dummy1x2dsss) ++#define WL_TX_POWER_OFDM80_CDD_FIRST OFFSETOF(txppr_t, b80_1x2cdd_ofdm) ++#define WL_TX_POWER_MCS80_CDD_FIRST OFFSETOF(txppr_t, b80_1x2cdd_mcs0) ++#define WL_TX_POWER_80_S1x2_FIRST OFFSETOF(txppr_t, b80_1x2cdd_mcs0) ++#define WL_TX_POWER_MCS80_STBC_FIRST OFFSETOF(txppr_t, b80_2x2stbc_mcs0) ++#define WL_TX_POWER_MCS80_SDM_FIRST OFFSETOF(txppr_t, b80_2x2sdm_mcs8) ++#define WL_TX_POWER_80_S2x2_FIRST OFFSETOF(txppr_t, b80_2x2sdm_mcs8) ++ ++#define WL_TX_POWER_80_DUMMY_CCK_CDD_S1x3_FIRST OFFSETOF(txppr_t, b80_dummy1x3dsss) ++#define WL_TX_POWER_OFDM80_CDD_S1x3_FIRST OFFSETOF(txppr_t, b80_1x3cdd_ofdm) ++#define WL_TX_POWER_80_S1x3_FIRST OFFSETOF(txppr_t, b80_1x3cdd_mcs0) ++#define WL_TX_POWER_80_STBC_S2x3_FIRST OFFSETOF(txppr_t, b80_2x3stbc_mcs0) ++#define WL_TX_POWER_80_S2x3_FIRST OFFSETOF(txppr_t, b80_2x3sdm_mcs8) ++#define WL_TX_POWER_80_S3x3_FIRST OFFSETOF(txppr_t, b80_3x3sdm_mcs16) ++ ++#define WL_TX_POWER_80_S1X1_VHT OFFSETOF(txppr_t, b80_1x1vht) ++#define WL_TX_POWER_80_S1X2_CDD_VHT OFFSETOF(txppr_t, b80_1x2cdd_vht) ++#define WL_TX_POWER_80_S2X2_STBC_VHT OFFSETOF(txppr_t, b80_2x2stbc_vht) ++#define WL_TX_POWER_80_S2X2_VHT OFFSETOF(txppr_t, b80_2x2sdm_vht) ++#define WL_TX_POWER_80_S1X3_CDD_VHT OFFSETOF(txppr_t, b80_1x3cdd_vht) ++#define WL_TX_POWER_80_S2X3_STBC_VHT OFFSETOF(txppr_t, b80_2x3stbc_vht) ++#define WL_TX_POWER_80_S2X3_VHT OFFSETOF(txppr_t, b80_2x3sdm_vht) ++#define WL_TX_POWER_80_S3X3_VHT OFFSETOF(txppr_t, b80_3x3sdm_vht) ++ ++/* 20 in 80MHz */ ++#define WL_TX_POWER_20UUL_CCK_FIRST OFFSETOF(txppr_t, b20in80_1x1dsss) ++#define WL_TX_POWER_20UUL_OFDM_FIRST OFFSETOF(txppr_t, b20in80_1x1ofdm) ++#define WL_TX_POWER_20UUL_S1x1_FIRST OFFSETOF(txppr_t, b20in80_1x1mcs0) ++ ++#define WL_TX_POWER_CCK_20UU_CDD_S1x2_FIRST OFFSETOF(txppr_t, b20in80_1x2dsss) ++#define WL_TX_POWER_20UUL_OFDM_CDD_FIRST OFFSETOF(txppr_t, b20in80_1x2cdd_ofdm) ++#define WL_TX_POWER_20UUL_S1x2_FIRST OFFSETOF(txppr_t, b20in80_1x2cdd_mcs0) ++#define WL_TX_POWER_20UUL_STBC_S2x2_FIRST OFFSETOF(txppr_t, b20in80_2x2stbc_mcs0) ++#define WL_TX_POWER_20UUL_S2x2_FIRST OFFSETOF(txppr_t, b20in80_2x2sdm_mcs8) ++ ++#define WL_TX_POWER_CCK_20UU_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20in80_1x3dsss) ++#define WL_TX_POWER_20UUL_OFDM_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20in80_1x3cdd_ofdm) ++#define WL_TX_POWER_20UUL_S1x3_FIRST OFFSETOF(txppr_t, b20in80_1x3cdd_mcs0) ++#define WL_TX_POWER_20UUL_STBC_S2x3_FIRST OFFSETOF(txppr_t, b20in80_2x3stbc_mcs0) ++#define WL_TX_POWER_20UUL_S2x3_FIRST OFFSETOF(txppr_t, b20in80_2x3sdm_mcs8) ++#define WL_TX_POWER_20UUL_S3x3_FIRST OFFSETOF(txppr_t, b20in80_3x3sdm_mcs16) ++ ++#define WL_TX_POWER_20UUL_S1X1_VHT OFFSETOF(txppr_t, b20in80_1x1vht) ++#define WL_TX_POWER_20UUL_S1X2_CDD_VHT OFFSETOF(txppr_t, b20in80_1x2cdd_vht) ++#define WL_TX_POWER_20UUL_S2X2_STBC_VHT OFFSETOF(txppr_t, b20in80_2x2stbc_vht) ++#define WL_TX_POWER_20UUL_S2X2_VHT OFFSETOF(txppr_t, b20in80_2x2sdm_vht) ++#define WL_TX_POWER_20UUL_S1X3_CDD_VHT OFFSETOF(txppr_t, b20in80_1x3cdd_vht) ++#define WL_TX_POWER_20UUL_S2X3_STBC_VHT OFFSETOF(txppr_t, b20in80_2x3stbc_vht) ++#define WL_TX_POWER_20UUL_S2X3_VHT OFFSETOF(txppr_t, b20in80_2x3sdm_vht) ++#define WL_TX_POWER_20UUL_S3X3_VHT OFFSETOF(txppr_t, b20in80_3x3sdm_vht) ++ ++/* 40 in 80MHz */ ++#define WL_TX_POWER_40UUL_DUMMY_CCK_FIRST OFFSETOF(txppr_t, b40in80_dummy1x1dsss) ++#define WL_TX_POWER_40UUL_OFDM_FIRST OFFSETOF(txppr_t, b40in80_1x1ofdm) ++#define WL_TX_POWER_40UUL_S1x1_FIRST OFFSETOF(txppr_t, b40in80_1x1mcs0) ++ ++#define WL_TX_POWER_CCK_40UU_DUMMY_CDD_S1x2_FIRST OFFSETOF(txppr_t, b40in80_dummy1x2dsss) ++#define WL_TX_POWER_40UUL_OFDM_CDD_FIRST OFFSETOF(txppr_t, b40in80_1x2cdd_ofdm) ++#define WL_TX_POWER_40UUL_S1x2_FIRST OFFSETOF(txppr_t, b40in80_1x2cdd_mcs0) ++#define WL_TX_POWER_40UUL_STBC_S2x2_FIRST OFFSETOF(txppr_t, b40in80_2x2stbc_mcs0) ++#define WL_TX_POWER_40UUL_S2x2_FIRST OFFSETOF(txppr_t, b40in80_2x2sdm_mcs8) ++ ++#define WL_TX_POWER_CCK_40UU_DUMMY_CDD_S1x3_FIRST OFFSETOF(txppr_t, b40in80_dummy1x3dsss) ++#define WL_TX_POWER_40UUL_OFDM_CDD_S1x3_FIRST OFFSETOF(txppr_t, b40in80_1x3cdd_ofdm) ++#define WL_TX_POWER_40UUL_S1x3_FIRST OFFSETOF(txppr_t, b40in80_1x3cdd_mcs0) ++#define WL_TX_POWER_40UUL_STBC_S2x3_FIRST OFFSETOF(txppr_t, b40in80_2x3stbc_mcs0) ++#define WL_TX_POWER_40UUL_S2x3_FIRST OFFSETOF(txppr_t, b40in80_2x3sdm_mcs8) ++#define WL_TX_POWER_40UUL_S3x3_FIRST OFFSETOF(txppr_t, b40in80_3x3sdm_mcs16) ++ ++#define WL_TX_POWER_40UUL_S1X1_VHT OFFSETOF(txppr_t, b40in80_1x1vht) ++#define WL_TX_POWER_40UUL_S1X2_CDD_VHT OFFSETOF(txppr_t, b40in80_1x2cdd_vht) ++#define WL_TX_POWER_40UUL_S2X2_STBC_VHT OFFSETOF(txppr_t, b40in80_2x2stbc_vht) ++#define WL_TX_POWER_40UUL_S2X2_VHT OFFSETOF(txppr_t, b40in80_2x2sdm_vht) ++#define WL_TX_POWER_40UUL_S1X3_CDD_VHT OFFSETOF(txppr_t, b40in80_1x3cdd_vht) ++#define WL_TX_POWER_40UUL_S2X3_STBC_VHT OFFSETOF(txppr_t, b40in80_2x3stbc_vht) ++#define WL_TX_POWER_40UUL_S2X3_VHT OFFSETOF(txppr_t, b40in80_2x3sdm_vht) ++#define WL_TX_POWER_40UUL_S3X3_VHT OFFSETOF(txppr_t, b40in80_3x3sdm_vht) ++ ++#define WL_TX_POWER_MCS_32 OFFSETOF(txppr_t, mcs32) /* C_CHECK remove later */ ++ ++#define WL_TX_POWER_RATES sizeof(struct txppr) ++ ++/* sslpnphy specifics */ ++#define WL_TX_POWER_MCS20_SISO_FIRST_SSN WL_TX_POWER_MCS20_SISO_FIRST ++#define WL_TX_POWER_MCS40_SISO_FIRST_SSN WL_TX_POWER_MCS40_SISO_FIRST ++ ++/* tx_power_t.flags bits */ ++#define WL_TX_POWER_F_ENABLED 1 ++#define WL_TX_POWER_F_HW 2 ++#define WL_TX_POWER_F_MIMO 4 ++#define WL_TX_POWER_F_SISO 8 ++#define WL_TX_POWER_F_HT 0x10 ++ ++typedef struct { ++ uint16 ver; /* version of this struct */ ++ uint16 len; /* length in bytes of this structure */ ++ uint32 flags; ++ chanspec_t chanspec; /* txpwr report for this channel */ ++ chanspec_t local_chanspec; /* channel on which we are associated */ ++ uint8 ppr[WL_TX_POWER_RATES]; /* Latest target power */ ++} wl_txppr_t; ++ ++#define WL_TXPPR_VERSION 0 ++#define WL_TXPPR_LENGTH (sizeof(wl_txppr_t)) ++#define TX_POWER_T_VERSION 43 ++ ++/* Defines used with channel_bandwidth for curpower */ ++#define WL_BW_20MHZ 0 ++#define WL_BW_40MHZ 1 ++#define WL_BW_80MHZ 2 ++ ++/* tx_power_t.flags bits */ ++#ifdef PPR_API ++#define WL_TX_POWER2_F_ENABLED 1 ++#define WL_TX_POWER2_F_HW 2 ++#define WL_TX_POWER2_F_MIMO 4 ++#define WL_TX_POWER2_F_SISO 8 ++#define WL_TX_POWER2_F_HT 0x10 ++#else ++#define WL_TX_POWER_F_ENABLED 1 ++#define WL_TX_POWER_F_HW 2 ++#define WL_TX_POWER_F_MIMO 4 ++#define WL_TX_POWER_F_SISO 8 ++#define WL_TX_POWER_F_HT 0x10 ++#endif ++typedef struct { ++ uint32 flags; ++ chanspec_t chanspec; /* txpwr report for this channel */ ++ chanspec_t local_chanspec; /* channel on which we are associated */ ++ uint8 local_max; /* local max according to the AP */ ++ uint8 local_constraint; /* local constraint according to the AP */ ++ int8 antgain[2]; /* Ant gain for each band - from SROM */ ++ uint8 rf_cores; /* count of RF Cores being reported */ ++ uint8 est_Pout[4]; /* Latest tx power out estimate per RF chain */ ++ uint8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain ++ * without adjustment ++ */ ++ uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ ++ uint8 tx_power_max[4]; /* Maximum target power among all rates */ ++ uint tx_power_max_rate_ind[4]; /* Index of the rate with the max target power */ ++ uint8 user_limit[WL_TX_POWER_RATES]; /* User limit */ ++ int8 board_limit[WL_TX_POWER_RATES]; /* Max power board can support (SROM) */ ++ int8 target[WL_TX_POWER_RATES]; /* Latest target power */ ++ int8 clm_limits[WL_NUMRATES]; /* regulatory limits - 20, 40 or 80MHz */ ++ int8 clm_limits_subchan1[WL_NUMRATES]; /* regulatory limits - 20in40 or 40in80 */ ++ int8 clm_limits_subchan2[WL_NUMRATES]; /* regulatory limits - 20in80MHz */ ++ int8 sar; /* SAR limit for display by wl executable */ ++ int8 channel_bandwidth; /* 20, 40 or 80 MHz bandwidth? */ ++ uint8 version; /* Version of the data format wlu <--> driver */ ++ uint8 display_core; /* Displayed curpower core */ ++#ifdef PPR_API ++} tx_power_new_t; ++#else ++} tx_power_t; ++#endif ++ ++typedef struct tx_inst_power { ++ uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ ++ uint8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ ++} tx_inst_power_t; ++ ++ ++typedef struct { ++ uint32 flags; ++ chanspec_t chanspec; /* txpwr report for this channel */ ++ chanspec_t local_chanspec; /* channel on which we are associated */ ++ uint8 local_max; /* local max according to the AP */ ++ uint8 local_constraint; /* local constraint according to the AP */ ++ int8 antgain[2]; /* Ant gain for each band - from SROM */ ++ uint8 rf_cores; /* count of RF Cores being reported */ ++ uint8 est_Pout[4]; /* Latest tx power out estimate per RF chain */ ++ uint8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain ++ * without adjustment ++ */ ++ uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ ++ uint8 tx_power_max[4]; /* Maximum target power among all rates */ ++ uint tx_power_max_rate_ind[4]; /* Index of the rate with the max target power */ ++ txppr_t user_limit; /* User limit */ ++ txppr_t reg_limit; /* Regulatory power limit */ ++ txppr_t board_limit; /* Max power board can support (SROM) */ ++ txppr_t target; /* Latest target power */ ++} wl_txpwr_t; ++ ++#define WL_NUM_TXCHAIN_MAX 4 ++typedef struct wl_txchain_pwr_offsets { ++ int8 offset[WL_NUM_TXCHAIN_MAX]; /* quarter dBm signed offset for each chain */ ++} wl_txchain_pwr_offsets_t; ++ ++/* 802.11h measurement types */ ++#define WLC_MEASURE_TPC 1 ++#define WLC_MEASURE_CHANNEL_BASIC 2 ++#define WLC_MEASURE_CHANNEL_CCA 3 ++#define WLC_MEASURE_CHANNEL_RPI 4 ++ ++/* regulatory enforcement levels */ ++#define SPECT_MNGMT_OFF 0 /* both 11h and 11d disabled */ ++#define SPECT_MNGMT_LOOSE_11H 1 /* allow non-11h APs in scan lists */ ++#define SPECT_MNGMT_STRICT_11H 2 /* prune out non-11h APs from scan list */ ++#define SPECT_MNGMT_STRICT_11D 3 /* switch to 802.11D mode */ ++/* SPECT_MNGMT_LOOSE_11H_D - same as SPECT_MNGMT_LOOSE with the exception that Country IE ++ * adoption is done regardless of capability spectrum_management ++ */ ++#define SPECT_MNGMT_LOOSE_11H_D 4 /* operation defined above */ ++ ++#define WL_CHAN_VALID_HW (1 << 0) /* valid with current HW */ ++#define WL_CHAN_VALID_SW (1 << 1) /* valid with current country setting */ ++#define WL_CHAN_BAND_5G (1 << 2) /* 5GHz-band channel */ ++#define WL_CHAN_RADAR (1 << 3) /* radar sensitive channel */ ++#define WL_CHAN_INACTIVE (1 << 4) /* temporarily inactive due to radar */ ++#define WL_CHAN_PASSIVE (1 << 5) /* channel is in passive mode */ ++#define WL_CHAN_RESTRICTED (1 << 6) /* restricted use channel */ ++ ++/* BTC mode used by "btc_mode" iovar */ ++#define WL_BTC_DISABLE 0 /* disable BT coexistence */ ++#define WL_BTC_FULLTDM 1 /* full TDM COEX */ ++#define WL_BTC_ENABLE 1 /* full TDM COEX to maintain backward compatiblity */ ++#define WL_BTC_PREMPT 2 /* full TDM COEX with preemption */ ++#define WL_BTC_LITE 3 /* light weight coex for large isolation platform */ ++#define WL_BTC_PARALLEL 4 /* BT and WLAN run in parallel with separate antenna */ ++#define WL_BTC_HYBRID 5 /* hybrid coex, only ack is allowed to transmit in BT slot */ ++#define WL_BTC_DEFAULT 8 /* set the default mode for the device */ ++#define WL_INF_BTC_DISABLE 0 ++#define WL_INF_BTC_ENABLE 1 ++#define WL_INF_BTC_AUTO 3 ++ ++/* BTC wire used by "btc_wire" iovar */ ++#define WL_BTC_DEFWIRE 0 /* use default wire setting */ ++#define WL_BTC_2WIRE 2 /* use 2-wire BTC */ ++#define WL_BTC_3WIRE 3 /* use 3-wire BTC */ ++#define WL_BTC_4WIRE 4 /* use 4-wire BTC */ ++ ++/* BTC flags: BTC configuration that can be set by host */ ++#define WL_BTC_FLAG_PREMPT (1 << 0) ++#define WL_BTC_FLAG_BT_DEF (1 << 1) ++#define WL_BTC_FLAG_ACTIVE_PROT (1 << 2) ++#define WL_BTC_FLAG_SIM_RSP (1 << 3) ++#define WL_BTC_FLAG_PS_PROTECT (1 << 4) ++#define WL_BTC_FLAG_SIM_TX_LP (1 << 5) ++#define WL_BTC_FLAG_ECI (1 << 6) ++#define WL_BTC_FLAG_LIGHT (1 << 7) ++#define WL_BTC_FLAG_PARALLEL (1 << 8) ++ ++/* Message levels */ ++#define WL_ERROR_VAL 0x00000001 ++#define WL_TRACE_VAL 0x00000002 ++#define WL_PRHDRS_VAL 0x00000004 ++#define WL_PRPKT_VAL 0x00000008 ++#define WL_INFORM_VAL 0x00000010 ++#define WL_TMP_VAL 0x00000020 ++#define WL_OID_VAL 0x00000040 ++#define WL_RATE_VAL 0x00000080 ++#define WL_ASSOC_VAL 0x00000100 ++#define WL_PRUSR_VAL 0x00000200 ++#define WL_PS_VAL 0x00000400 ++#define WL_TXPWR_VAL 0x00000800 /* retired in TOT on 6/10/2009 */ ++#define WL_PORT_VAL 0x00001000 ++#define WL_DUAL_VAL 0x00002000 ++#define WL_WSEC_VAL 0x00004000 ++#define WL_WSEC_DUMP_VAL 0x00008000 ++#define WL_LOG_VAL 0x00010000 ++#define WL_NRSSI_VAL 0x00020000 /* retired in TOT on 6/10/2009 */ ++#define WL_LOFT_VAL 0x00040000 /* retired in TOT on 6/10/2009 */ ++#define WL_REGULATORY_VAL 0x00080000 ++#define WL_PHYCAL_VAL 0x00100000 /* retired in TOT on 6/10/2009 */ ++#define WL_RADAR_VAL 0x00200000 /* retired in TOT on 6/10/2009 */ ++#define WL_MPC_VAL 0x00400000 ++#define WL_APSTA_VAL 0x00800000 ++#define WL_DFS_VAL 0x01000000 ++#define WL_BA_VAL 0x02000000 /* retired in TOT on 6/14/2010 */ ++#define WL_ACI_VAL 0x04000000 ++#define WL_MBSS_VAL 0x04000000 ++#define WL_CAC_VAL 0x08000000 ++#define WL_AMSDU_VAL 0x10000000 ++#define WL_AMPDU_VAL 0x20000000 ++#define WL_FFPLD_VAL 0x40000000 ++ ++/* wl_msg_level is full. For new bits take the next one and AND with ++ * wl_msg_level2 in wl_dbg.h ++ */ ++#define WL_DPT_VAL 0x00000001 ++#define WL_SCAN_VAL 0x00000002 ++#define WL_WOWL_VAL 0x00000004 ++#define WL_COEX_VAL 0x00000008 ++#define WL_RTDC_VAL 0x00000010 ++#define WL_PROTO_VAL 0x00000020 ++#define WL_BTA_VAL 0x00000040 ++#define WL_CHANINT_VAL 0x00000080 ++#define WL_THERMAL_VAL 0x00000100 /* retired in TOT on 6/10/2009 */ ++#define WL_P2P_VAL 0x00000200 ++#define WL_ITFR_VAL 0x00000400 ++#define WL_MCHAN_VAL 0x00000800 ++#define WL_TDLS_VAL 0x00001000 ++#define WL_MCNX_VAL 0x00002000 ++#define WL_PROT_VAL 0x00004000 ++#define WL_PSTA_VAL 0x00008000 ++#define WL_TBTT_VAL 0x00010000 ++#define WL_NIC_VAL 0x00020000 ++#define WL_PWRSEL_VAL 0x00040000 ++/* use top-bit for WL_TIME_STAMP_VAL because this is a modifier ++ * rather than a message-type of its own ++ */ ++#define WL_TIMESTAMP_VAL 0x80000000 ++ ++/* max # of leds supported by GPIO (gpio pin# == led index#) */ ++#define WL_LED_NUMGPIO 32 /* gpio 0-31 */ ++ ++/* led per-pin behaviors */ ++#define WL_LED_OFF 0 /* always off */ ++#define WL_LED_ON 1 /* always on */ ++#define WL_LED_ACTIVITY 2 /* activity */ ++#define WL_LED_RADIO 3 /* radio enabled */ ++#define WL_LED_ARADIO 4 /* 5 Ghz radio enabled */ ++#define WL_LED_BRADIO 5 /* 2.4Ghz radio enabled */ ++#define WL_LED_BGMODE 6 /* on if gmode, off if bmode */ ++#define WL_LED_WI1 7 ++#define WL_LED_WI2 8 ++#define WL_LED_WI3 9 ++#define WL_LED_ASSOC 10 /* associated state indicator */ ++#define WL_LED_INACTIVE 11 /* null behavior (clears default behavior) */ ++#define WL_LED_ASSOCACT 12 /* on when associated; blink fast for activity */ ++#define WL_LED_WI4 13 ++#define WL_LED_WI5 14 ++#define WL_LED_BLINKSLOW 15 /* blink slow */ ++#define WL_LED_BLINKMED 16 /* blink med */ ++#define WL_LED_BLINKFAST 17 /* blink fast */ ++#define WL_LED_BLINKCUSTOM 18 /* blink custom */ ++#define WL_LED_BLINKPERIODIC 19 /* blink periodic (custom 1000ms / off 400ms) */ ++#define WL_LED_ASSOC_WITH_SEC 20 /* when connected with security */ ++ /* keep on for 300 sec */ ++#define WL_LED_START_OFF 21 /* off upon boot, could be turned on later */ ++#define WL_LED_NUMBEHAVIOR 22 ++ ++/* led behavior numeric value format */ ++#define WL_LED_BEH_MASK 0x7f /* behavior mask */ ++#define WL_LED_AL_MASK 0x80 /* activelow (polarity) bit */ ++ ++/* maximum channels returned by the get valid channels iovar */ ++#define WL_NUMCHANNELS 64 ++ ++/* max number of chanspecs (used by the iovar to calc. buf space) */ ++#define WL_NUMCHANSPECS 110 ++ ++/* WDS link local endpoint WPA role */ ++#define WL_WDS_WPA_ROLE_AUTH 0 /* authenticator */ ++#define WL_WDS_WPA_ROLE_SUP 1 /* supplicant */ ++#define WL_WDS_WPA_ROLE_AUTO 255 /* auto, based on mac addr value */ ++ ++/* number of bytes needed to define a 128-bit mask for MAC event reporting */ ++#define WL_EVENTING_MASK_LEN 16 ++ ++/* ++ * Join preference iovar value is an array of tuples. Each tuple has a one-byte type, ++ * a one-byte length, and a variable length value. RSSI type tuple must be present ++ * in the array. ++ * ++ * Types are defined in "join preference types" section. ++ * ++ * Length is the value size in octets. It is reserved for WL_JOIN_PREF_WPA type tuple ++ * and must be set to zero. ++ * ++ * Values are defined below. ++ * ++ * 1. RSSI - 2 octets ++ * offset 0: reserved ++ * offset 1: reserved ++ * ++ * 2. WPA - 2 + 12 * n octets (n is # tuples defined below) ++ * offset 0: reserved ++ * offset 1: # of tuples ++ * offset 2: tuple 1 ++ * offset 14: tuple 2 ++ * ... ++ * offset 2 + 12 * (n - 1) octets: tuple n ++ * ++ * struct wpa_cfg_tuple { ++ * uint8 akm[DOT11_OUI_LEN+1]; akm suite ++ * uint8 ucipher[DOT11_OUI_LEN+1]; unicast cipher suite ++ * uint8 mcipher[DOT11_OUI_LEN+1]; multicast cipher suite ++ * }; ++ * ++ * multicast cipher suite can be specified as a specific cipher suite or WL_WPA_ACP_MCS_ANY. ++ * ++ * 3. BAND - 2 octets ++ * offset 0: reserved ++ * offset 1: see "band preference" and "band types" ++ * ++ * 4. BAND RSSI - 2 octets ++ * offset 0: band types ++ * offset 1: +ve RSSI boost balue in dB ++ */ ++ ++/* join preference types */ ++#define WL_JOIN_PREF_RSSI 1 /* by RSSI */ ++#define WL_JOIN_PREF_WPA 2 /* by akm and ciphers */ ++#define WL_JOIN_PREF_BAND 3 /* by 802.11 band */ ++#define WL_JOIN_PREF_RSSI_DELTA 4 /* by 802.11 band only if RSSI delta condition matches */ ++#define WL_JOIN_PREF_TRANS_PREF 5 /* defined by requesting AP */ ++ ++/* band preference */ ++#define WLJP_BAND_ASSOC_PREF 255 /* use what WLC_SET_ASSOC_PREFER ioctl specifies */ ++ ++/* any multicast cipher suite */ ++#define WL_WPA_ACP_MCS_ANY "\x00\x00\x00\x00" ++ ++struct tsinfo_arg { ++ uint8 octets[3]; ++}; ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++#define NFIFO 6 /* # tx/rx fifopairs */ ++ ++#define WL_CNT_T_VERSION 8 /* current version of wl_cnt_t struct */ ++ ++typedef struct { ++ uint16 version; /* see definition of WL_CNT_T_VERSION */ ++ uint16 length; /* length of entire structure */ ++ ++ /* transmit stat counters */ ++ uint32 txframe; /* tx data frames */ ++ uint32 txbyte; /* tx data bytes */ ++ uint32 txretrans; /* tx mac retransmits */ ++ uint32 txerror; /* tx data errors (derived: sum of others) */ ++ uint32 txctl; /* tx management frames */ ++ uint32 txprshort; /* tx short preamble frames */ ++ uint32 txserr; /* tx status errors */ ++ uint32 txnobuf; /* tx out of buffers errors */ ++ uint32 txnoassoc; /* tx discard because we're not associated */ ++ uint32 txrunt; /* tx runt frames */ ++ uint32 txchit; /* tx header cache hit (fastpath) */ ++ uint32 txcmiss; /* tx header cache miss (slowpath) */ ++ ++ /* transmit chip error counters */ ++ uint32 txuflo; /* tx fifo underflows */ ++ uint32 txphyerr; /* tx phy errors (indicated in tx status) */ ++ uint32 txphycrs; ++ ++ /* receive stat counters */ ++ uint32 rxframe; /* rx data frames */ ++ uint32 rxbyte; /* rx data bytes */ ++ uint32 rxerror; /* rx data errors (derived: sum of others) */ ++ uint32 rxctl; /* rx management frames */ ++ uint32 rxnobuf; /* rx out of buffers errors */ ++ uint32 rxnondata; /* rx non data frames in the data channel errors */ ++ uint32 rxbadds; /* rx bad DS errors */ ++ uint32 rxbadcm; /* rx bad control or management frames */ ++ uint32 rxfragerr; /* rx fragmentation errors */ ++ uint32 rxrunt; /* rx runt frames */ ++ uint32 rxgiant; /* rx giant frames */ ++ uint32 rxnoscb; /* rx no scb error */ ++ uint32 rxbadproto; /* rx invalid frames */ ++ uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */ ++ uint32 rxbadda; /* rx frames tossed for invalid da */ ++ uint32 rxfilter; /* rx frames filtered out */ ++ ++ /* receive chip error counters */ ++ uint32 rxoflo; /* rx fifo overflow errors */ ++ uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */ ++ ++ uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */ ++ uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */ ++ uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */ ++ ++ /* misc counters */ ++ uint32 dmade; /* tx/rx dma descriptor errors */ ++ uint32 dmada; /* tx/rx dma data errors */ ++ uint32 dmape; /* tx/rx dma descriptor protocol errors */ ++ uint32 reset; /* reset count */ ++ uint32 tbtt; /* cnts the TBTT int's */ ++ uint32 txdmawar; ++ uint32 pkt_callback_reg_fail; /* callbacks register failure */ ++ ++ /* MAC counters: 32-bit version of d11.h's macstat_t */ ++ uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, ++ * Control Management (includes retransmissions) ++ */ ++ uint32 txrtsfrm; /* number of RTS sent out by the MAC */ ++ uint32 txctsfrm; /* number of CTS sent out by the MAC */ ++ uint32 txackfrm; /* number of ACK frames sent out */ ++ uint32 txdnlfrm; /* Not used */ ++ uint32 txbcnfrm; /* beacons transmitted */ ++ uint32 txfunfl[8]; /* per-fifo tx underflows */ ++ uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS ++ * or BCN) ++ */ ++ uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for ++ * driver enqueued frames ++ */ ++ uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */ ++ uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */ ++ uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not ++ * data/control/management ++ */ ++ uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ ++ uint32 rxbadplcp; /* parity check of the PLCP header failed */ ++ uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ ++ uint32 rxstrt; /* Number of received frames with a good PLCP ++ * (i.e. passing parity check) ++ */ ++ uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ ++ uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ ++ uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */ ++ uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ ++ uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ ++ uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ ++ uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */ ++ uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */ ++ uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */ ++ uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */ ++ uint32 rxctsocast; /* number of received CTS not addressed to the MAC */ ++ uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */ ++ uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */ ++ uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC ++ * (unlikely to see these) ++ */ ++ uint32 rxbeaconmbss; /* beacons received from member of BSS */ ++ uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from ++ * other BSS (WDS FRAME) ++ */ ++ uint32 rxbeaconobss; /* beacons received from other BSS */ ++ uint32 rxrsptmout; /* Number of response timeouts for transmitted frames ++ * expecting a response ++ */ ++ uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */ ++ uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */ ++ uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */ ++ uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */ ++ uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */ ++ uint32 pmqovfl; /* Number of PMQ overflows */ ++ uint32 rxcgprqfrm; /* Number of received Probe requests that made it into ++ * the PRQ fifo ++ */ ++ uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */ ++ uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did ++ * not get ACK ++ */ ++ uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */ ++ uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ ++ * fifo because a probe response could not be sent out within ++ * the time limit defined in M_PRS_MAXTIME ++ */ ++ uint32 rxnack; /* obsolete */ ++ uint32 frmscons; /* obsolete */ ++ uint32 txnack; /* obsolete */ ++ uint32 txglitch_nack; /* obsolete */ ++ uint32 txburst; /* obsolete */ ++ ++ /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ ++ uint32 txfrag; /* dot11TransmittedFragmentCount */ ++ uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ ++ uint32 txfail; /* dot11FailedCount */ ++ uint32 txretry; /* dot11RetryCount */ ++ uint32 txretrie; /* dot11MultipleRetryCount */ ++ uint32 rxdup; /* dot11FrameduplicateCount */ ++ uint32 txrts; /* dot11RTSSuccessCount */ ++ uint32 txnocts; /* dot11RTSFailureCount */ ++ uint32 txnoack; /* dot11ACKFailureCount */ ++ uint32 rxfrag; /* dot11ReceivedFragmentCount */ ++ uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ ++ uint32 rxcrc; /* dot11FCSErrorCount */ ++ uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */ ++ uint32 rxundec; /* dot11WEPUndecryptableCount */ ++ ++ /* WPA2 counters (see rxundec for DecryptFailureCount) */ ++ uint32 tkipmicfaill; /* TKIPLocalMICFailures */ ++ uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */ ++ uint32 tkipreplay; /* TKIPReplays */ ++ uint32 ccmpfmterr; /* CCMPFormatErrors */ ++ uint32 ccmpreplay; /* CCMPReplays */ ++ uint32 ccmpundec; /* CCMPDecryptErrors */ ++ uint32 fourwayfail; /* FourWayHandshakeFailures */ ++ uint32 wepundec; /* dot11WEPUndecryptableCount */ ++ uint32 wepicverr; /* dot11WEPICVErrorCount */ ++ uint32 decsuccess; /* DecryptSuccessCount */ ++ uint32 tkipicverr; /* TKIPICVErrorCount */ ++ uint32 wepexcluded; /* dot11WEPExcludedCount */ ++ ++ uint32 txchanrej; /* Tx frames suppressed due to channel rejection */ ++ uint32 psmwds; /* Count PSM watchdogs */ ++ uint32 phywatchdog; /* Count Phy watchdogs (triggered by ucode) */ ++ ++ /* MBSS counters, AP only */ ++ uint32 prq_entries_handled; /* PRQ entries read in */ ++ uint32 prq_undirected_entries; /* which were bcast bss & ssid */ ++ uint32 prq_bad_entries; /* which could not be translated to info */ ++ uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */ ++ uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */ ++ uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */ ++ uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */ ++ ++ /* per-rate receive stat counters */ ++ uint32 rx1mbps; /* packets rx at 1Mbps */ ++ uint32 rx2mbps; /* packets rx at 2Mbps */ ++ uint32 rx5mbps5; /* packets rx at 5.5Mbps */ ++ uint32 rx6mbps; /* packets rx at 6Mbps */ ++ uint32 rx9mbps; /* packets rx at 9Mbps */ ++ uint32 rx11mbps; /* packets rx at 11Mbps */ ++ uint32 rx12mbps; /* packets rx at 12Mbps */ ++ uint32 rx18mbps; /* packets rx at 18Mbps */ ++ uint32 rx24mbps; /* packets rx at 24Mbps */ ++ uint32 rx36mbps; /* packets rx at 36Mbps */ ++ uint32 rx48mbps; /* packets rx at 48Mbps */ ++ uint32 rx54mbps; /* packets rx at 54Mbps */ ++ uint32 rx108mbps; /* packets rx at 108mbps */ ++ uint32 rx162mbps; /* packets rx at 162mbps */ ++ uint32 rx216mbps; /* packets rx at 216 mbps */ ++ uint32 rx270mbps; /* packets rx at 270 mbps */ ++ uint32 rx324mbps; /* packets rx at 324 mbps */ ++ uint32 rx378mbps; /* packets rx at 378 mbps */ ++ uint32 rx432mbps; /* packets rx at 432 mbps */ ++ uint32 rx486mbps; /* packets rx at 486 mbps */ ++ uint32 rx540mbps; /* packets rx at 540 mbps */ ++ ++ /* pkteng rx frame stats */ ++ uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */ ++ uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */ ++ ++ uint32 rfdisable; /* count of radio disables */ ++ uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ ++ ++ uint32 txexptime; /* Tx frames suppressed due to timer expiration */ ++ ++ uint32 txmpdu_sgi; /* count for sgi transmit */ ++ uint32 rxmpdu_sgi; /* count for sgi received */ ++ uint32 txmpdu_stbc; /* count for stbc transmit */ ++ uint32 rxmpdu_stbc; /* count for stbc received */ ++ ++ uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */ ++ ++ /* WPA2 counters (see rxundec for DecryptFailureCount) */ ++ uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */ ++ uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */ ++ uint32 tkipreplay_mcst; /* TKIPReplays */ ++ uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */ ++ uint32 ccmpreplay_mcst; /* CCMPReplays */ ++ uint32 ccmpundec_mcst; /* CCMPDecryptErrors */ ++ uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */ ++ uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */ ++ uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */ ++ uint32 decsuccess_mcst; /* DecryptSuccessCount */ ++ uint32 tkipicverr_mcst; /* TKIPICVErrorCount */ ++ uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */ ++ ++ uint32 dma_hang; /* count for dma hang */ ++ uint32 reinit; /* count for reinit */ ++ ++ uint32 pstatxucast; /* count of ucast frames xmitted on all psta assoc */ ++ uint32 pstatxnoassoc; /* count of txnoassoc frames xmitted on all psta assoc */ ++ uint32 pstarxucast; /* count of ucast frames received on all psta assoc */ ++ uint32 pstarxbcmc; /* count of bcmc frames received on all psta */ ++ uint32 pstatxbcmc; /* count of bcmc frames transmitted on all psta */ ++ ++ uint32 cso_passthrough; /* hw cso required but passthrough */ ++} wl_cnt_t; ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++typedef struct { ++ uint16 version; /* see definition of WL_CNT_T_VERSION */ ++ uint16 length; /* length of entire structure */ ++ ++ /* transmit stat counters */ ++ uint32 txframe; /* tx data frames */ ++ uint32 txbyte; /* tx data bytes */ ++ uint32 txretrans; /* tx mac retransmits */ ++ uint32 txerror; /* tx data errors (derived: sum of others) */ ++ uint32 txctl; /* tx management frames */ ++ uint32 txprshort; /* tx short preamble frames */ ++ uint32 txserr; /* tx status errors */ ++ uint32 txnobuf; /* tx out of buffers errors */ ++ uint32 txnoassoc; /* tx discard because we're not associated */ ++ uint32 txrunt; /* tx runt frames */ ++ uint32 txchit; /* tx header cache hit (fastpath) */ ++ uint32 txcmiss; /* tx header cache miss (slowpath) */ ++ ++ /* transmit chip error counters */ ++ uint32 txuflo; /* tx fifo underflows */ ++ uint32 txphyerr; /* tx phy errors (indicated in tx status) */ ++ uint32 txphycrs; ++ ++ /* receive stat counters */ ++ uint32 rxframe; /* rx data frames */ ++ uint32 rxbyte; /* rx data bytes */ ++ uint32 rxerror; /* rx data errors (derived: sum of others) */ ++ uint32 rxctl; /* rx management frames */ ++ uint32 rxnobuf; /* rx out of buffers errors */ ++ uint32 rxnondata; /* rx non data frames in the data channel errors */ ++ uint32 rxbadds; /* rx bad DS errors */ ++ uint32 rxbadcm; /* rx bad control or management frames */ ++ uint32 rxfragerr; /* rx fragmentation errors */ ++ uint32 rxrunt; /* rx runt frames */ ++ uint32 rxgiant; /* rx giant frames */ ++ uint32 rxnoscb; /* rx no scb error */ ++ uint32 rxbadproto; /* rx invalid frames */ ++ uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */ ++ uint32 rxbadda; /* rx frames tossed for invalid da */ ++ uint32 rxfilter; /* rx frames filtered out */ ++ ++ /* receive chip error counters */ ++ uint32 rxoflo; /* rx fifo overflow errors */ ++ uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */ ++ ++ uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */ ++ uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */ ++ uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */ ++ ++ /* misc counters */ ++ uint32 dmade; /* tx/rx dma descriptor errors */ ++ uint32 dmada; /* tx/rx dma data errors */ ++ uint32 dmape; /* tx/rx dma descriptor protocol errors */ ++ uint32 reset; /* reset count */ ++ uint32 tbtt; /* cnts the TBTT int's */ ++ uint32 txdmawar; ++ uint32 pkt_callback_reg_fail; /* callbacks register failure */ ++ ++ /* MAC counters: 32-bit version of d11.h's macstat_t */ ++ uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, ++ * Control Management (includes retransmissions) ++ */ ++ uint32 txrtsfrm; /* number of RTS sent out by the MAC */ ++ uint32 txctsfrm; /* number of CTS sent out by the MAC */ ++ uint32 txackfrm; /* number of ACK frames sent out */ ++ uint32 txdnlfrm; /* Not used */ ++ uint32 txbcnfrm; /* beacons transmitted */ ++ uint32 txfunfl[8]; /* per-fifo tx underflows */ ++ uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS ++ * or BCN) ++ */ ++ uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for ++ * driver enqueued frames ++ */ ++ uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */ ++ uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */ ++ uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not ++ * data/control/management ++ */ ++ uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ ++ uint32 rxbadplcp; /* parity check of the PLCP header failed */ ++ uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ ++ uint32 rxstrt; /* Number of received frames with a good PLCP ++ * (i.e. passing parity check) ++ */ ++ uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ ++ uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ ++ uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */ ++ uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ ++ uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ ++ uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ ++ uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */ ++ uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */ ++ uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */ ++ uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */ ++ uint32 rxctsocast; /* number of received CTS not addressed to the MAC */ ++ uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */ ++ uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */ ++ uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC ++ * (unlikely to see these) ++ */ ++ uint32 rxbeaconmbss; /* beacons received from member of BSS */ ++ uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from ++ * other BSS (WDS FRAME) ++ */ ++ uint32 rxbeaconobss; /* beacons received from other BSS */ ++ uint32 rxrsptmout; /* Number of response timeouts for transmitted frames ++ * expecting a response ++ */ ++ uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */ ++ uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */ ++ uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */ ++ uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */ ++ uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */ ++ uint32 pmqovfl; /* Number of PMQ overflows */ ++ uint32 rxcgprqfrm; /* Number of received Probe requests that made it into ++ * the PRQ fifo ++ */ ++ uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */ ++ uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did ++ * not get ACK ++ */ ++ uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */ ++ uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ ++ * fifo because a probe response could not be sent out within ++ * the time limit defined in M_PRS_MAXTIME ++ */ ++ uint32 rxnack; ++ uint32 frmscons; ++ uint32 txnack; ++ uint32 txglitch_nack; /* obsolete */ ++ uint32 txburst; /* obsolete */ ++ ++ /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ ++ uint32 txfrag; /* dot11TransmittedFragmentCount */ ++ uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ ++ uint32 txfail; /* dot11FailedCount */ ++ uint32 txretry; /* dot11RetryCount */ ++ uint32 txretrie; /* dot11MultipleRetryCount */ ++ uint32 rxdup; /* dot11FrameduplicateCount */ ++ uint32 txrts; /* dot11RTSSuccessCount */ ++ uint32 txnocts; /* dot11RTSFailureCount */ ++ uint32 txnoack; /* dot11ACKFailureCount */ ++ uint32 rxfrag; /* dot11ReceivedFragmentCount */ ++ uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ ++ uint32 rxcrc; /* dot11FCSErrorCount */ ++ uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */ ++ uint32 rxundec; /* dot11WEPUndecryptableCount */ ++ ++ /* WPA2 counters (see rxundec for DecryptFailureCount) */ ++ uint32 tkipmicfaill; /* TKIPLocalMICFailures */ ++ uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */ ++ uint32 tkipreplay; /* TKIPReplays */ ++ uint32 ccmpfmterr; /* CCMPFormatErrors */ ++ uint32 ccmpreplay; /* CCMPReplays */ ++ uint32 ccmpundec; /* CCMPDecryptErrors */ ++ uint32 fourwayfail; /* FourWayHandshakeFailures */ ++ uint32 wepundec; /* dot11WEPUndecryptableCount */ ++ uint32 wepicverr; /* dot11WEPICVErrorCount */ ++ uint32 decsuccess; /* DecryptSuccessCount */ ++ uint32 tkipicverr; /* TKIPICVErrorCount */ ++ uint32 wepexcluded; /* dot11WEPExcludedCount */ ++ ++ uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */ ++ ++ /* WPA2 counters (see rxundec for DecryptFailureCount) */ ++ uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */ ++ uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */ ++ uint32 tkipreplay_mcst; /* TKIPReplays */ ++ uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */ ++ uint32 ccmpreplay_mcst; /* CCMPReplays */ ++ uint32 ccmpundec_mcst; /* CCMPDecryptErrors */ ++ uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */ ++ uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */ ++ uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */ ++ uint32 decsuccess_mcst; /* DecryptSuccessCount */ ++ uint32 tkipicverr_mcst; /* TKIPICVErrorCount */ ++ uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */ ++ ++ uint32 txchanrej; /* Tx frames suppressed due to channel rejection */ ++ uint32 txexptime; /* Tx frames suppressed due to timer expiration */ ++ uint32 psmwds; /* Count PSM watchdogs */ ++ uint32 phywatchdog; /* Count Phy watchdogs (triggered by ucode) */ ++ ++ /* MBSS counters, AP only */ ++ uint32 prq_entries_handled; /* PRQ entries read in */ ++ uint32 prq_undirected_entries; /* which were bcast bss & ssid */ ++ uint32 prq_bad_entries; /* which could not be translated to info */ ++ uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */ ++ uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */ ++ uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */ ++ uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */ ++ ++ /* per-rate receive stat counters */ ++ uint32 rx1mbps; /* packets rx at 1Mbps */ ++ uint32 rx2mbps; /* packets rx at 2Mbps */ ++ uint32 rx5mbps5; /* packets rx at 5.5Mbps */ ++ uint32 rx6mbps; /* packets rx at 6Mbps */ ++ uint32 rx9mbps; /* packets rx at 9Mbps */ ++ uint32 rx11mbps; /* packets rx at 11Mbps */ ++ uint32 rx12mbps; /* packets rx at 12Mbps */ ++ uint32 rx18mbps; /* packets rx at 18Mbps */ ++ uint32 rx24mbps; /* packets rx at 24Mbps */ ++ uint32 rx36mbps; /* packets rx at 36Mbps */ ++ uint32 rx48mbps; /* packets rx at 48Mbps */ ++ uint32 rx54mbps; /* packets rx at 54Mbps */ ++ uint32 rx108mbps; /* packets rx at 108mbps */ ++ uint32 rx162mbps; /* packets rx at 162mbps */ ++ uint32 rx216mbps; /* packets rx at 216 mbps */ ++ uint32 rx270mbps; /* packets rx at 270 mbps */ ++ uint32 rx324mbps; /* packets rx at 324 mbps */ ++ uint32 rx378mbps; /* packets rx at 378 mbps */ ++ uint32 rx432mbps; /* packets rx at 432 mbps */ ++ uint32 rx486mbps; /* packets rx at 486 mbps */ ++ uint32 rx540mbps; /* packets rx at 540 mbps */ ++ ++ /* pkteng rx frame stats */ ++ uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */ ++ uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */ ++ ++ uint32 rfdisable; /* count of radio disables */ ++ uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ ++ ++ uint32 txmpdu_sgi; /* count for sgi transmit */ ++ uint32 rxmpdu_sgi; /* count for sgi received */ ++ uint32 txmpdu_stbc; /* count for stbc transmit */ ++ uint32 rxmpdu_stbc; /* count for stbc received */ ++} wl_cnt_ver_six_t; ++ ++#define WL_DELTA_STATS_T_VERSION 1 /* current version of wl_delta_stats_t struct */ ++ ++typedef struct { ++ uint16 version; /* see definition of WL_DELTA_STATS_T_VERSION */ ++ uint16 length; /* length of entire structure */ ++ ++ /* transmit stat counters */ ++ uint32 txframe; /* tx data frames */ ++ uint32 txbyte; /* tx data bytes */ ++ uint32 txretrans; /* tx mac retransmits */ ++ uint32 txfail; /* tx failures */ ++ ++ /* receive stat counters */ ++ uint32 rxframe; /* rx data frames */ ++ uint32 rxbyte; /* rx data bytes */ ++ ++ /* per-rate receive stat counters */ ++ uint32 rx1mbps; /* packets rx at 1Mbps */ ++ uint32 rx2mbps; /* packets rx at 2Mbps */ ++ uint32 rx5mbps5; /* packets rx at 5.5Mbps */ ++ uint32 rx6mbps; /* packets rx at 6Mbps */ ++ uint32 rx9mbps; /* packets rx at 9Mbps */ ++ uint32 rx11mbps; /* packets rx at 11Mbps */ ++ uint32 rx12mbps; /* packets rx at 12Mbps */ ++ uint32 rx18mbps; /* packets rx at 18Mbps */ ++ uint32 rx24mbps; /* packets rx at 24Mbps */ ++ uint32 rx36mbps; /* packets rx at 36Mbps */ ++ uint32 rx48mbps; /* packets rx at 48Mbps */ ++ uint32 rx54mbps; /* packets rx at 54Mbps */ ++ uint32 rx108mbps; /* packets rx at 108mbps */ ++ uint32 rx162mbps; /* packets rx at 162mbps */ ++ uint32 rx216mbps; /* packets rx at 216 mbps */ ++ uint32 rx270mbps; /* packets rx at 270 mbps */ ++ uint32 rx324mbps; /* packets rx at 324 mbps */ ++ uint32 rx378mbps; /* packets rx at 378 mbps */ ++ uint32 rx432mbps; /* packets rx at 432 mbps */ ++ uint32 rx486mbps; /* packets rx at 486 mbps */ ++ uint32 rx540mbps; /* packets rx at 540 mbps */ ++} wl_delta_stats_t; ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++#define WL_WME_CNT_VERSION 1 /* current version of wl_wme_cnt_t */ ++ ++typedef struct { ++ uint32 packets; ++ uint32 bytes; ++} wl_traffic_stats_t; ++ ++typedef struct { ++ uint16 version; /* see definition of WL_WME_CNT_VERSION */ ++ uint16 length; /* length of entire structure */ ++ ++ wl_traffic_stats_t tx[AC_COUNT]; /* Packets transmitted */ ++ wl_traffic_stats_t tx_failed[AC_COUNT]; /* Packets dropped or failed to transmit */ ++ wl_traffic_stats_t rx[AC_COUNT]; /* Packets received */ ++ wl_traffic_stats_t rx_failed[AC_COUNT]; /* Packets failed to receive */ ++ ++ wl_traffic_stats_t forward[AC_COUNT]; /* Packets forwarded by AP */ ++ ++ wl_traffic_stats_t tx_expired[AC_COUNT]; /* packets dropped due to lifetime expiry */ ++ ++} wl_wme_cnt_t; ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++struct wl_msglevel2 { ++ uint32 low; ++ uint32 high; ++}; ++ ++typedef struct wl_mkeep_alive_pkt { ++ uint16 version; /* Version for mkeep_alive */ ++ uint16 length; /* length of fixed parameters in the structure */ ++ uint32 period_msec; ++ uint16 len_bytes; ++ uint8 keep_alive_id; /* 0 - 3 for N = 4 */ ++ uint8 data[1]; ++} wl_mkeep_alive_pkt_t; ++ ++#define WL_MKEEP_ALIVE_VERSION 1 ++#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data) ++#define WL_MKEEP_ALIVE_PRECISION 500 ++ ++#ifdef WLBA ++ ++#define WLC_BA_CNT_VERSION 1 /* current version of wlc_ba_cnt_t */ ++ ++/* block ack related stats */ ++typedef struct wlc_ba_cnt { ++ uint16 version; /* WLC_BA_CNT_VERSION */ ++ uint16 length; /* length of entire structure */ ++ ++ /* transmit stat counters */ ++ uint32 txpdu; /* pdus sent */ ++ uint32 txsdu; /* sdus sent */ ++ uint32 txfc; /* tx side flow controlled packets */ ++ uint32 txfci; /* tx side flow control initiated */ ++ uint32 txretrans; /* retransmitted pdus */ ++ uint32 txbatimer; /* ba resend due to timer */ ++ uint32 txdrop; /* dropped packets */ ++ uint32 txaddbareq; /* addba req sent */ ++ uint32 txaddbaresp; /* addba resp sent */ ++ uint32 txdelba; /* delba sent */ ++ uint32 txba; /* ba sent */ ++ uint32 txbar; /* bar sent */ ++ uint32 txpad[4]; /* future */ ++ ++ /* receive side counters */ ++ uint32 rxpdu; /* pdus recd */ ++ uint32 rxqed; /* pdus buffered before sending up */ ++ uint32 rxdup; /* duplicate pdus */ ++ uint32 rxnobuf; /* pdus discarded due to no buf */ ++ uint32 rxaddbareq; /* addba req recd */ ++ uint32 rxaddbaresp; /* addba resp recd */ ++ uint32 rxdelba; /* delba recd */ ++ uint32 rxba; /* ba recd */ ++ uint32 rxbar; /* bar recd */ ++ uint32 rxinvba; /* invalid ba recd */ ++ uint32 rxbaholes; /* ba recd with holes */ ++ uint32 rxunexp; /* unexpected packets */ ++ uint32 rxpad[4]; /* future */ ++} wlc_ba_cnt_t; ++#endif /* WLBA */ ++ ++/* structure for per-tid ampdu control */ ++struct ampdu_tid_control { ++ uint8 tid; /* tid */ ++ uint8 enable; /* enable/disable */ ++}; ++ ++/* structure for identifying ea/tid for sending addba/delba */ ++struct ampdu_ea_tid { ++ struct ether_addr ea; /* Station address */ ++ uint8 tid; /* tid */ ++}; ++/* structure for identifying retry/tid for retry_limit_tid/rr_retry_limit_tid */ ++struct ampdu_retry_tid { ++ uint8 tid; /* tid */ ++ uint8 retry; /* retry value */ ++}; ++ ++/* Different discovery modes for dpt */ ++#define DPT_DISCOVERY_MANUAL 0x01 /* manual discovery mode */ ++#define DPT_DISCOVERY_AUTO 0x02 /* auto discovery mode */ ++#define DPT_DISCOVERY_SCAN 0x04 /* scan-based discovery mode */ ++ ++/* different path selection values */ ++#define DPT_PATHSEL_AUTO 0 /* auto mode for path selection */ ++#define DPT_PATHSEL_DIRECT 1 /* always use direct DPT path */ ++#define DPT_PATHSEL_APPATH 2 /* always use AP path */ ++ ++/* different ops for deny list */ ++#define DPT_DENY_LIST_ADD 1 /* add to dpt deny list */ ++#define DPT_DENY_LIST_REMOVE 2 /* remove from dpt deny list */ ++ ++/* different ops for manual end point */ ++#define DPT_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ ++#define DPT_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ ++#define DPT_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ ++ ++/* structure for dpt iovars */ ++typedef struct dpt_iovar { ++ struct ether_addr ea; /* Station address */ ++ uint8 mode; /* mode: depends on iovar */ ++ uint32 pad; /* future */ ++} dpt_iovar_t; ++ ++/* flags to indicate DPT status */ ++#define DPT_STATUS_ACTIVE 0x01 /* link active (though may be suspended) */ ++#define DPT_STATUS_AES 0x02 /* link secured through AES encryption */ ++#define DPT_STATUS_FAILED 0x04 /* DPT link failed */ ++ ++#define DPT_FNAME_LEN 48 /* Max length of friendly name */ ++ ++typedef struct dpt_status { ++ uint8 status; /* flags to indicate status */ ++ uint8 fnlen; /* length of friendly name */ ++ uchar name[DPT_FNAME_LEN]; /* friendly name */ ++ uint32 rssi; /* RSSI of the link */ ++ sta_info_t sta; /* sta info */ ++} dpt_status_t; ++ ++/* structure for dpt list */ ++typedef struct dpt_list { ++ uint32 num; /* number of entries in struct */ ++ dpt_status_t status[1]; /* per station info */ ++} dpt_list_t; ++ ++/* structure for dpt friendly name */ ++typedef struct dpt_fname { ++ uint8 len; /* length of friendly name */ ++ uchar name[DPT_FNAME_LEN]; /* friendly name */ ++} dpt_fname_t; ++ ++#define BDD_FNAME_LEN 32 /* Max length of friendly name */ ++typedef struct bdd_fname { ++ uint8 len; /* length of friendly name */ ++ uchar name[BDD_FNAME_LEN]; /* friendly name */ ++} bdd_fname_t; ++ ++/* structure for addts arguments */ ++/* For ioctls that take a list of TSPEC */ ++struct tslist { ++ int count; /* number of tspecs */ ++ struct tsinfo_arg tsinfo[1]; /* variable length array of tsinfo */ ++}; ++ ++#ifdef WLTDLS ++/* different ops for manual end point */ ++#define TDLS_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ ++#define TDLS_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ ++#define TDLS_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ ++#define TDLS_MANUAL_EP_PM 4 /* put dpt endpoint in PM mode */ ++#define TDLS_MANUAL_EP_WAKE 5 /* wake up dpt endpoint from PM */ ++#define TDLS_MANUAL_EP_DISCOVERY 6 /* discover if endpoint is TDLS capable */ ++#define TDLS_MANUAL_EP_CHSW 7 /* channel switch */ ++ ++/* structure for tdls iovars */ ++typedef struct tdls_iovar { ++ struct ether_addr ea; /* Station address */ ++ uint8 mode; /* mode: depends on iovar */ ++ chanspec_t chanspec; ++ uint32 pad; /* future */ ++} tdls_iovar_t; ++ ++/* modes */ ++#define TDLS_WFD_IE_TX 0 ++#define TDLS_WFD_IE_RX 1 ++#define TDLS_WFD_IE_SIZE 255 ++/* structure for tdls wfd ie */ ++typedef struct tdls_wfd_ie_iovar { ++ struct ether_addr ea; /* Station address */ ++ uint8 mode; ++ uint8 length; ++ uint8 data[TDLS_WFD_IE_SIZE]; ++} tdls_wfd_ie_iovar_t; ++#endif /* WLTDLS */ ++ ++/* structure for addts/delts arguments */ ++typedef struct tspec_arg { ++ uint16 version; /* see definition of TSPEC_ARG_VERSION */ ++ uint16 length; /* length of entire structure */ ++ uint flag; /* bit field */ ++ /* TSPEC Arguments */ ++ struct tsinfo_arg tsinfo; /* TS Info bit field */ ++ uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ ++ uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ ++ uint min_srv_interval; /* Minimum Service Interval (us) */ ++ uint max_srv_interval; /* Maximum Service Interval (us) */ ++ uint inactivity_interval; /* Inactivity Interval (us) */ ++ uint suspension_interval; /* Suspension Interval (us) */ ++ uint srv_start_time; /* Service Start Time (us) */ ++ uint min_data_rate; /* Minimum Data Rate (bps) */ ++ uint mean_data_rate; /* Mean Data Rate (bps) */ ++ uint peak_data_rate; /* Peak Data Rate (bps) */ ++ uint max_burst_size; /* Maximum Burst Size (bytes) */ ++ uint delay_bound; /* Delay Bound (us) */ ++ uint min_phy_rate; /* Minimum PHY Rate (bps) */ ++ uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0 to 8.0) */ ++ uint16 medium_time; /* Medium Time (32 us/s periods) */ ++ uint8 dialog_token; /* dialog token */ ++} tspec_arg_t; ++ ++/* tspec arg for desired station */ ++typedef struct tspec_per_sta_arg { ++ struct ether_addr ea; ++ struct tspec_arg ts; ++} tspec_per_sta_arg_t; ++ ++/* structure for max bandwidth for each access category */ ++typedef struct wme_max_bandwidth { ++ uint32 ac[AC_COUNT]; /* max bandwidth for each access category */ ++} wme_max_bandwidth_t; ++ ++#define WL_WME_MBW_PARAMS_IO_BYTES (sizeof(wme_max_bandwidth_t)) ++ ++/* current version of wl_tspec_arg_t struct */ ++#define TSPEC_ARG_VERSION 2 /* current version of wl_tspec_arg_t struct */ ++#define TSPEC_ARG_LENGTH 55 /* argument length from tsinfo to medium_time */ ++#define TSPEC_DEFAULT_DIALOG_TOKEN 42 /* default dialog token */ ++#define TSPEC_DEFAULT_SBW_FACTOR 0x3000 /* default surplus bw */ ++ ++ ++#define WL_WOWL_KEEPALIVE_MAX_PACKET_SIZE 80 ++#define WLC_WOWL_MAX_KEEPALIVE 2 ++ ++/* define for flag */ ++#define TSPEC_PENDING 0 /* TSPEC pending */ ++#define TSPEC_ACCEPTED 1 /* TSPEC accepted */ ++#define TSPEC_REJECTED 2 /* TSPEC rejected */ ++#define TSPEC_UNKNOWN 3 /* TSPEC unknown */ ++#define TSPEC_STATUS_MASK 7 /* TSPEC status mask */ ++ ++ ++/* Software feature flag defines used by wlfeatureflag */ ++#ifdef WLAFTERBURNER ++#define WL_SWFL_ABBFL 0x0001 /* Allow Afterburner on systems w/o hardware BFL */ ++#define WL_SWFL_ABENCORE 0x0002 /* Allow AB on non-4318E chips */ ++#endif /* WLAFTERBURNER */ ++#define WL_SWFL_NOHWRADIO 0x0004 ++#define WL_SWFL_FLOWCONTROL 0x0008 /* Enable backpressure to OS stack */ ++#define WL_SWFL_WLBSSSORT 0x0010 /* Per-port supports sorting of BSS */ ++ ++#define WL_LIFETIME_MAX 0xFFFF /* Max value in ms */ ++ ++/* Packet lifetime configuration per ac */ ++typedef struct wl_lifetime { ++ uint32 ac; /* access class */ ++ uint32 lifetime; /* Packet lifetime value in ms */ ++} wl_lifetime_t; ++ ++/* Channel Switch Announcement param */ ++typedef struct wl_chan_switch { ++ uint8 mode; /* value 0 or 1 */ ++ uint8 count; /* count # of beacons before switching */ ++ chanspec_t chspec; /* chanspec */ ++ uint8 reg; /* regulatory class */ ++} wl_chan_switch_t; ++ ++/* Roaming trigger definitions for WLC_SET_ROAM_TRIGGER. ++ * ++ * (-100 < value < 0) value is used directly as a roaming trigger in dBm ++ * (0 <= value) value specifies a logical roaming trigger level from ++ * the list below ++ * ++ * WLC_GET_ROAM_TRIGGER always returns roaming trigger value in dBm, never ++ * the logical roam trigger value. ++ */ ++#define WLC_ROAM_TRIGGER_DEFAULT 0 /* default roaming trigger */ ++#define WLC_ROAM_TRIGGER_BANDWIDTH 1 /* optimize for bandwidth roaming trigger */ ++#define WLC_ROAM_TRIGGER_DISTANCE 2 /* optimize for distance roaming trigger */ ++#define WLC_ROAM_TRIGGER_AUTO 3 /* auto-detect environment */ ++#define WLC_ROAM_TRIGGER_MAX_VALUE 3 /* max. valid value */ ++ ++#define WLC_ROAM_NEVER_ROAM_TRIGGER (-100) /* Avoid Roaming by setting a large value */ ++ ++/* Preferred Network Offload (PNO, formerly PFN) defines */ ++#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ ++ ++enum { ++ PFN_LIST_ORDER, ++ PFN_RSSI ++}; ++ ++enum { ++ DISABLE, ++ ENABLE ++}; ++ ++enum { ++ OFF_ADAPT, ++ SMART_ADAPT, ++ STRICT_ADAPT, ++ SLOW_ADAPT ++}; ++ ++#define SORT_CRITERIA_BIT 0 ++#define AUTO_NET_SWITCH_BIT 1 ++#define ENABLE_BKGRD_SCAN_BIT 2 ++#define IMMEDIATE_SCAN_BIT 3 ++#define AUTO_CONNECT_BIT 4 ++#define ENABLE_BD_SCAN_BIT 5 ++#define ENABLE_ADAPTSCAN_BIT 6 ++#define IMMEDIATE_EVENT_BIT 8 ++#define SUPPRESS_SSID_BIT 9 ++#define ENABLE_NET_OFFLOAD_BIT 10 ++ ++#define SORT_CRITERIA_MASK 0x0001 ++#define AUTO_NET_SWITCH_MASK 0x0002 ++#define ENABLE_BKGRD_SCAN_MASK 0x0004 ++#define IMMEDIATE_SCAN_MASK 0x0008 ++#define AUTO_CONNECT_MASK 0x0010 ++ ++#define ENABLE_BD_SCAN_MASK 0x0020 ++#define ENABLE_ADAPTSCAN_MASK 0x00c0 ++#define IMMEDIATE_EVENT_MASK 0x0100 ++#define SUPPRESS_SSID_MASK 0x0200 ++#define ENABLE_NET_OFFLOAD_MASK 0x0400 ++ ++#define PFN_VERSION 2 ++#define PFN_SCANRESULT_VERSION 1 ++#define MAX_PFN_LIST_COUNT 16 ++ ++#define PFN_COMPLETE 1 ++#define PFN_INCOMPLETE 0 ++ ++#define DEFAULT_BESTN 2 ++#define DEFAULT_MSCAN 0 ++#define DEFAULT_REPEAT 10 ++#define DEFAULT_EXP 2 ++ ++/* PFN network info structure */ ++typedef struct wl_pfn_subnet_info { ++ struct ether_addr BSSID; ++ uint8 channel; /* channel number only */ ++ uint8 SSID_len; ++ uint8 SSID[32]; ++} wl_pfn_subnet_info_t; ++ ++typedef struct wl_pfn_net_info { ++ wl_pfn_subnet_info_t pfnsubnet; ++ int16 RSSI; /* receive signal strength (in dBm) */ ++ uint16 timestamp; /* age in seconds */ ++} wl_pfn_net_info_t; ++ ++typedef struct wl_pfn_scanresults { ++ uint32 version; ++ uint32 status; ++ uint32 count; ++ wl_pfn_net_info_t netinfo[1]; ++} wl_pfn_scanresults_t; ++ ++/* PFN data structure */ ++typedef struct wl_pfn_param { ++ int32 version; /* PNO parameters version */ ++ int32 scan_freq; /* Scan frequency */ ++ int32 lost_network_timeout; /* Timeout in sec. to declare ++ * discovered network as lost ++ */ ++ int16 flags; /* Bit field to control features ++ * of PFN such as sort criteria auto ++ * enable switch and background scan ++ */ ++ int16 rssi_margin; /* Margin to avoid jitter for choosing a ++ * PFN based on RSSI sort criteria ++ */ ++ uint8 bestn; /* number of best networks in each scan */ ++ uint8 mscan; /* number of scans recorded */ ++ uint8 repeat; /* Minimum number of scan intervals ++ *before scan frequency changes in adaptive scan ++ */ ++ uint8 exp; /* Exponent of 2 for maximum scan interval */ ++ int32 slow_freq; /* slow scan period */ ++} wl_pfn_param_t; ++ ++typedef struct wl_pfn_bssid { ++ struct ether_addr macaddr; ++ /* Bit4: suppress_lost, Bit3: suppress_found */ ++ uint16 flags; ++} wl_pfn_bssid_t; ++#define WL_PFN_SUPPRESSFOUND_MASK 0x08 ++#define WL_PFN_SUPPRESSLOST_MASK 0x10 ++ ++typedef struct wl_pfn_cfg { ++ uint32 reporttype; ++ int32 channel_num; ++ uint16 channel_list[WL_NUMCHANNELS]; ++} wl_pfn_cfg_t; ++#define WL_PFN_REPORT_ALLNET 0 ++#define WL_PFN_REPORT_SSIDNET 1 ++#define WL_PFN_REPORT_BSSIDNET 2 ++ ++typedef struct wl_pfn { ++ wlc_ssid_t ssid; /* ssid name and its length */ ++ int32 flags; /* bit2: hidden */ ++ int32 infra; /* BSS Vs IBSS */ ++ int32 auth; /* Open Vs Closed */ ++ int32 wpa_auth; /* WPA type */ ++ int32 wsec; /* wsec value */ ++} wl_pfn_t; ++#define WL_PFN_HIDDEN_BIT 2 ++#define PNO_SCAN_MAX_FW 508*1000 /* max time scan time in msec */ ++#define PNO_SCAN_MAX_FW_SEC PNO_SCAN_MAX_FW/1000 /* max time scan time in SEC */ ++#define PNO_SCAN_MIN_FW_SEC 10 /* min time scan time in SEC */ ++#define WL_PFN_HIDDEN_MASK 0x4 ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* TCP Checksum Offload defines */ ++#define TOE_TX_CSUM_OL 0x00000001 ++#define TOE_RX_CSUM_OL 0x00000002 ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++/* TCP Checksum Offload error injection for testing */ ++#define TOE_ERRTEST_TX_CSUM 0x00000001 ++#define TOE_ERRTEST_RX_CSUM 0x00000002 ++#define TOE_ERRTEST_RX_CSUM2 0x00000004 ++ ++struct toe_ol_stats_t { ++ /* Num of tx packets that don't need to be checksummed */ ++ uint32 tx_summed; ++ ++ /* Num of tx packets where checksum is filled by offload engine */ ++ uint32 tx_iph_fill; ++ uint32 tx_tcp_fill; ++ uint32 tx_udp_fill; ++ uint32 tx_icmp_fill; ++ ++ /* Num of rx packets where toe finds out if checksum is good or bad */ ++ uint32 rx_iph_good; ++ uint32 rx_iph_bad; ++ uint32 rx_tcp_good; ++ uint32 rx_tcp_bad; ++ uint32 rx_udp_good; ++ uint32 rx_udp_bad; ++ uint32 rx_icmp_good; ++ uint32 rx_icmp_bad; ++ ++ /* Num of tx packets in which csum error is injected */ ++ uint32 tx_tcp_errinj; ++ uint32 tx_udp_errinj; ++ uint32 tx_icmp_errinj; ++ ++ /* Num of rx packets in which csum error is injected */ ++ uint32 rx_tcp_errinj; ++ uint32 rx_udp_errinj; ++ uint32 rx_icmp_errinj; ++}; ++ ++/* ARP Offload feature flags for arp_ol iovar */ ++#define ARP_OL_AGENT 0x00000001 ++#define ARP_OL_SNOOP 0x00000002 ++#define ARP_OL_HOST_AUTO_REPLY 0x00000004 ++#define ARP_OL_PEER_AUTO_REPLY 0x00000008 ++ ++/* ARP Offload error injection */ ++#define ARP_ERRTEST_REPLY_PEER 0x1 ++#define ARP_ERRTEST_REPLY_HOST 0x2 ++ ++#define ARP_MULTIHOMING_MAX 8 /* Maximum local host IP addresses */ ++#define ND_MULTIHOMING_MAX 8 /* Maximum local host IP addresses */ ++ ++/* Arp offload statistic counts */ ++struct arp_ol_stats_t { ++ uint32 host_ip_entries; /* Host IP table addresses (more than one if multihomed) */ ++ uint32 host_ip_overflow; /* Host IP table additions skipped due to overflow */ ++ ++ uint32 arp_table_entries; /* ARP table entries */ ++ uint32 arp_table_overflow; /* ARP table additions skipped due to overflow */ ++ ++ uint32 host_request; /* ARP requests from host */ ++ uint32 host_reply; /* ARP replies from host */ ++ uint32 host_service; /* ARP requests from host serviced by ARP Agent */ ++ ++ uint32 peer_request; /* ARP requests received from network */ ++ uint32 peer_request_drop; /* ARP requests from network that were dropped */ ++ uint32 peer_reply; /* ARP replies received from network */ ++ uint32 peer_reply_drop; /* ARP replies from network that were dropped */ ++ uint32 peer_service; /* ARP request from host serviced by ARP Agent */ ++}; ++ ++/* NS offload statistic counts */ ++struct nd_ol_stats_t { ++ uint32 host_ip_entries; /* Host IP table addresses (more than one if multihomed) */ ++ uint32 host_ip_overflow; /* Host IP table additions skipped due to overflow */ ++ uint32 peer_request; /* NS requests received from network */ ++ uint32 peer_request_drop; /* NS requests from network that were dropped */ ++ uint32 peer_reply_drop; /* NA replies from network that were dropped */ ++ uint32 peer_service; /* NS request from host serviced by firmware */ ++}; ++ ++/* ++ * Keep-alive packet offloading. ++ */ ++ ++/* NAT keep-alive packets format: specifies the re-transmission period, the packet ++ * length, and packet contents. ++ */ ++typedef struct wl_keep_alive_pkt { ++ uint32 period_msec; /* Retransmission period (0 to disable packet re-transmits) */ ++ uint16 len_bytes; /* Size of packet to transmit (0 to disable packet re-transmits) */ ++ uint8 data[1]; /* Variable length packet to transmit. Contents should include ++ * entire ethernet packet (enet header, IP header, UDP header, ++ * and UDP payload) in network byte order. ++ */ ++} wl_keep_alive_pkt_t; ++ ++#define WL_KEEP_ALIVE_FIXED_LEN OFFSETOF(wl_keep_alive_pkt_t, data) ++ ++/* ++ * Dongle pattern matching filter. ++ */ ++ ++/* Packet filter types. Currently, only pattern matching is supported. */ ++typedef enum wl_pkt_filter_type { ++ WL_PKT_FILTER_TYPE_PATTERN_MATCH /* Pattern matching filter */ ++} wl_pkt_filter_type_t; ++ ++#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t ++ ++/* Pattern matching filter. Specifies an offset within received packets to ++ * start matching, the pattern to match, the size of the pattern, and a bitmask ++ * that indicates which bits within the pattern should be matched. ++ */ ++typedef struct wl_pkt_filter_pattern { ++ uint32 offset; /* Offset within received packet to start pattern matching. ++ * Offset '0' is the first byte of the ethernet header. ++ */ ++ uint32 size_bytes; /* Size of the pattern. Bitmask must be the same size. */ ++ uint8 mask_and_pattern[1]; /* Variable length mask and pattern data. mask starts ++ * at offset 0. Pattern immediately follows mask. ++ */ ++} wl_pkt_filter_pattern_t; ++ ++/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ ++typedef struct wl_pkt_filter { ++ uint32 id; /* Unique filter id, specified by app. */ ++ uint32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */ ++ uint32 negate_match; /* Negate the result of filter matches */ ++ union { /* Filter definitions */ ++ wl_pkt_filter_pattern_t pattern; /* Pattern matching filter */ ++ } u; ++} wl_pkt_filter_t; ++ ++#define WL_PKT_FILTER_FIXED_LEN OFFSETOF(wl_pkt_filter_t, u) ++#define WL_PKT_FILTER_PATTERN_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_t, mask_and_pattern) ++ ++/* IOVAR "pkt_filter_enable" parameter. */ ++typedef struct wl_pkt_filter_enable { ++ uint32 id; /* Unique filter id */ ++ uint32 enable; /* Enable/disable bool */ ++} wl_pkt_filter_enable_t; ++ ++/* IOVAR "pkt_filter_list" parameter. Used to retrieve a list of installed filters. */ ++typedef struct wl_pkt_filter_list { ++ uint32 num; /* Number of installed packet filters */ ++ wl_pkt_filter_t filter[1]; /* Variable array of packet filters. */ ++} wl_pkt_filter_list_t; ++ ++#define WL_PKT_FILTER_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_list_t, filter) ++ ++/* IOVAR "pkt_filter_stats" parameter. Used to retrieve debug statistics. */ ++typedef struct wl_pkt_filter_stats { ++ uint32 num_pkts_matched; /* # filter matches for specified filter id */ ++ uint32 num_pkts_forwarded; /* # packets fwded from dongle to host for all filters */ ++ uint32 num_pkts_discarded; /* # packets discarded by dongle for all filters */ ++} wl_pkt_filter_stats_t; ++ ++/* Sequential Commands ioctl */ ++typedef struct wl_seq_cmd_ioctl { ++ uint32 cmd; /* common ioctl definition */ ++ uint32 len; /* length of user buffer */ ++} wl_seq_cmd_ioctl_t; ++ ++#define WL_SEQ_CMD_ALIGN_BYTES 4 ++ ++/* These are the set of get IOCTLs that should be allowed when using ++ * IOCTL sequence commands. These are issued implicitly by wl.exe each time ++ * it is invoked. We never want to buffer these, or else wl.exe will stop working. ++ */ ++#define WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd) \ ++ (((cmd) == WLC_GET_MAGIC) || \ ++ ((cmd) == WLC_GET_VERSION) || \ ++ ((cmd) == WLC_GET_AP) || \ ++ ((cmd) == WLC_GET_INSTANCE)) ++ ++/* ++ * Packet engine interface ++ */ ++ ++#define WL_PKTENG_PER_TX_START 0x01 ++#define WL_PKTENG_PER_TX_STOP 0x02 ++#define WL_PKTENG_PER_RX_START 0x04 ++#define WL_PKTENG_PER_RX_WITH_ACK_START 0x05 ++#define WL_PKTENG_PER_TX_WITH_ACK_START 0x06 ++#define WL_PKTENG_PER_RX_STOP 0x08 ++#define WL_PKTENG_PER_MASK 0xff ++ ++#define WL_PKTENG_SYNCHRONOUS 0x100 /* synchronous flag */ ++ ++typedef struct wl_pkteng { ++ uint32 flags; ++ uint32 delay; /* Inter-packet delay */ ++ uint32 nframes; /* Number of frames */ ++ uint32 length; /* Packet length */ ++ uint8 seqno; /* Enable/disable sequence no. */ ++ struct ether_addr dest; /* Destination address */ ++ struct ether_addr src; /* Source address */ ++} wl_pkteng_t; ++ ++#define NUM_80211b_RATES 4 ++#define NUM_80211ag_RATES 8 ++#define NUM_80211n_RATES 32 ++#define NUM_80211_RATES (NUM_80211b_RATES+NUM_80211ag_RATES+NUM_80211n_RATES) ++typedef struct wl_pkteng_stats { ++ uint32 lostfrmcnt; /* RX PER test: no of frames lost (skip seqno) */ ++ int32 rssi; /* RSSI */ ++ int32 snr; /* signal to noise ratio */ ++ uint16 rxpktcnt[NUM_80211_RATES+1]; ++} wl_pkteng_stats_t; ++ ++ ++#define WL_WOWL_MAGIC (1 << 0) /* Wakeup on Magic packet */ ++#define WL_WOWL_NET (1 << 1) /* Wakeup on Netpattern */ ++#define WL_WOWL_DIS (1 << 2) /* Wakeup on loss-of-link due to Disassoc/Deauth */ ++#define WL_WOWL_RETR (1 << 3) /* Wakeup on retrograde TSF */ ++#define WL_WOWL_BCN (1 << 4) /* Wakeup on loss of beacon */ ++#define WL_WOWL_TST (1 << 5) /* Wakeup after test */ ++#define WL_WOWL_M1 (1 << 6) /* Wakeup after PTK refresh */ ++#define WL_WOWL_EAPID (1 << 7) /* Wakeup after receipt of EAP-Identity Req */ ++#define WL_WOWL_PME_GPIO (1 << 8) /* Wakeind via PME(0) or GPIO(1) */ ++#define WL_WOWL_NEEDTKIP1 (1 << 9) /* need tkip phase 1 key to be updated by the driver */ ++#define WL_WOWL_GTK_FAILURE (1 << 10) /* enable wakeup if GTK fails */ ++#define WL_WOWL_EXTMAGPAT (1 << 11) /* support extended magic packets */ ++#define WL_WOWL_ARPOFFLOAD (1 << 12) /* support ARP/NS/keepalive offloading */ ++#define WL_WOWL_WPA2 (1 << 13) /* read protocol version for EAPOL frames */ ++#define WL_WOWL_KEYROT (1 << 14) /* If the bit is set, use key rotaton */ ++#define WL_WOWL_BCAST (1 << 15) /* If the bit is set, frm received was bcast frame */ ++ ++#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */ ++ ++#define WOWL_PATTEN_TYPE_ARP (1 << 0) /* ARP offload Pattern */ ++#define WOWL_PATTEN_TYPE_NA (1 << 1) /* NA offload Pattern */ ++ ++typedef struct { ++ uint32 masksize; /* Size of the mask in #of bytes */ ++ uint32 offset; /* Offset to start looking for the packet in # of bytes */ ++ uint32 patternoffset; /* Offset of start of pattern in the structure */ ++ uint32 patternsize; /* Size of the pattern itself in #of bytes */ ++ uint32 id; /* id */ ++ uint32 reasonsize; /* Size of the wakeup reason code */ ++ uint32 flags; /* Flags to tell the pattern type and other properties */ ++ /* Mask follows the structure above */ ++ /* Pattern follows the mask is at 'patternoffset' from the start */ ++} wl_wowl_pattern_t; ++ ++typedef struct { ++ uint count; ++ wl_wowl_pattern_t pattern[1]; ++} wl_wowl_pattern_list_t; ++ ++typedef struct { ++ uint8 pci_wakeind; /* Whether PCI PMECSR PMEStatus bit was set */ ++ uint16 ucode_wakeind; /* What wakeup-event indication was set by ucode */ ++} wl_wowl_wakeind_t; ++ ++ ++/* per AC rate control related data structure */ ++typedef struct wl_txrate_class { ++ uint8 init_rate; ++ uint8 min_rate; ++ uint8 max_rate; ++} wl_txrate_class_t; ++ ++ ++ ++/* Overlap BSS Scan parameters default, minimum, maximum */ ++#define WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT 20 /* unit TU */ ++#define WLC_OBSS_SCAN_PASSIVE_DWELL_MIN 5 /* unit TU */ ++#define WLC_OBSS_SCAN_PASSIVE_DWELL_MAX 1000 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT 10 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_DWELL_MIN 10 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_DWELL_MAX 1000 /* unit TU */ ++#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT 300 /* unit Sec */ ++#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN 10 /* unit Sec */ ++#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX 900 /* unit Sec */ ++#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT 5 ++#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN 5 ++#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX 100 ++#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT 200 /* unit TU */ ++#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN 200 /* unit TU */ ++#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT 20 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN 20 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT 25 /* unit percent */ ++#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN 0 /* unit percent */ ++#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX 100 /* unit percent */ ++ ++/* structure for Overlap BSS scan arguments */ ++typedef struct wl_obss_scan_arg { ++ int16 passive_dwell; ++ int16 active_dwell; ++ int16 bss_widthscan_interval; ++ int16 passive_total; ++ int16 active_total; ++ int16 chanwidth_transition_delay; ++ int16 activity_threshold; ++} wl_obss_scan_arg_t; ++ ++#define WL_OBSS_SCAN_PARAM_LEN sizeof(wl_obss_scan_arg_t) ++#define WL_MIN_NUM_OBSS_SCAN_ARG 7 /* minimum number of arguments required for OBSS Scan */ ++ ++#define WL_COEX_INFO_MASK 0x07 ++#define WL_COEX_INFO_REQ 0x01 ++#define WL_COEX_40MHZ_INTOLERANT 0x02 ++#define WL_COEX_WIDTH20 0x04 ++ ++#define WLC_RSSI_INVALID 0 /* invalid RSSI value */ ++ ++#define MAX_RSSI_LEVELS 8 ++ ++/* RSSI event notification configuration. */ ++typedef struct wl_rssi_event { ++ uint32 rate_limit_msec; /* # of events posted to application will be limited to ++ * one per specified period (0 to disable rate limit). ++ */ ++ uint8 num_rssi_levels; /* Number of entries in rssi_levels[] below */ ++ int8 rssi_levels[MAX_RSSI_LEVELS]; /* Variable number of RSSI levels. An event ++ * will be posted each time the RSSI of received ++ * beacons/packets crosses a level. ++ */ ++} wl_rssi_event_t; ++ ++typedef struct wl_action_obss_coex_req { ++ uint8 info; ++ uint8 num; ++ uint8 ch_list[1]; ++} wl_action_obss_coex_req_t; ++ ++ ++/* IOVar parameter block for small MAC address array with type indicator */ ++#define WL_IOV_MAC_PARAM_LEN 4 ++ ++#define WL_IOV_PKTQ_LOG_PRECS 16 ++ ++typedef struct { ++ uint32 num_addrs; ++ char addr_type[WL_IOV_MAC_PARAM_LEN]; ++ struct ether_addr ea[WL_IOV_MAC_PARAM_LEN]; ++} wl_iov_mac_params_t; ++ ++ ++/* Parameter block for PKTQ_LOG statistics */ ++typedef struct { ++ uint32 requested; /* packets requested to be stored */ ++ uint32 stored; /* packets stored */ ++ uint32 saved; /* packets saved, ++ because a lowest priority queue has given away one packet ++ */ ++ uint32 selfsaved; /* packets saved, ++ because an older packet from the same queue has been dropped ++ */ ++ uint32 full_dropped; /* packets dropped, ++ because pktq is full with higher precedence packets ++ */ ++ uint32 dropped; /* packets dropped because pktq per that precedence is full */ ++ uint32 sacrificed; /* packets dropped, ++ in order to save one from a queue of a highest priority ++ */ ++ uint32 busy; /* packets droped because of hardware/transmission error */ ++ uint32 retry; /* packets re-sent because they were not received */ ++ uint32 ps_retry; /* packets retried again prior to moving power save mode */ ++ uint32 retry_drop; /* packets finally dropped after retry limit */ ++ uint32 max_avail; /* the high-water mark of the queue capacity for packets - ++ goes to zero as queue fills ++ */ ++ uint32 max_used; /* the high-water mark of the queue utilisation for packets - ++ increases with use ('inverse' of max_avail) ++ */ ++ uint32 queue_capacity; /* the maximum capacity of the queue */ ++} pktq_log_counters_v01_t; ++ ++#define sacrified sacrificed ++ ++typedef struct { ++ uint8 num_prec[WL_IOV_MAC_PARAM_LEN]; ++ pktq_log_counters_v01_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; ++ char headings[1]; ++} pktq_log_format_v01_t; ++ ++ ++typedef struct { ++ uint32 version; ++ wl_iov_mac_params_t params; ++ union { ++ pktq_log_format_v01_t v01; ++ } pktq_log; ++} wl_iov_pktq_log_t; ++ ++ ++/* **** EXTLOG **** */ ++#define EXTLOG_CUR_VER 0x0100 ++ ++#define MAX_ARGSTR_LEN 18 /* At least big enough for storing ETHER_ADDR_STR_LEN */ ++ ++/* log modules (bitmap) */ ++#define LOG_MODULE_COMMON 0x0001 ++#define LOG_MODULE_ASSOC 0x0002 ++#define LOG_MODULE_EVENT 0x0004 ++#define LOG_MODULE_MAX 3 /* Update when adding module */ ++ ++/* log levels */ ++#define WL_LOG_LEVEL_DISABLE 0 ++#define WL_LOG_LEVEL_ERR 1 ++#define WL_LOG_LEVEL_WARN 2 ++#define WL_LOG_LEVEL_INFO 3 ++#define WL_LOG_LEVEL_MAX WL_LOG_LEVEL_INFO /* Update when adding level */ ++ ++/* flag */ ++#define LOG_FLAG_EVENT 1 ++ ++/* log arg_type */ ++#define LOG_ARGTYPE_NULL 0 ++#define LOG_ARGTYPE_STR 1 /* %s */ ++#define LOG_ARGTYPE_INT 2 /* %d */ ++#define LOG_ARGTYPE_INT_STR 3 /* %d...%s */ ++#define LOG_ARGTYPE_STR_INT 4 /* %s...%d */ ++ ++typedef struct wlc_extlog_cfg { ++ int max_number; ++ uint16 module; /* bitmap */ ++ uint8 level; ++ uint8 flag; ++ uint16 version; ++} wlc_extlog_cfg_t; ++ ++typedef struct log_record { ++ uint32 time; ++ uint16 module; ++ uint16 id; ++ uint8 level; ++ uint8 sub_unit; ++ uint8 seq_num; ++ int32 arg; ++ char str[MAX_ARGSTR_LEN]; ++} log_record_t; ++ ++typedef struct wlc_extlog_req { ++ uint32 from_last; ++ uint32 num; ++} wlc_extlog_req_t; ++ ++typedef struct wlc_extlog_results { ++ uint16 version; ++ uint16 record_len; ++ uint32 num; ++ log_record_t logs[1]; ++} wlc_extlog_results_t; ++ ++typedef struct log_idstr { ++ uint16 id; ++ uint16 flag; ++ uint8 arg_type; ++ const char *fmt_str; ++} log_idstr_t; ++ ++#define FMTSTRF_USER 1 ++ ++/* flat ID definitions ++ * New definitions HAVE TO BE ADDED at the end of the table. Otherwise, it will ++ * affect backward compatibility with pre-existing apps ++ */ ++typedef enum { ++ FMTSTR_DRIVER_UP_ID = 0, ++ FMTSTR_DRIVER_DOWN_ID = 1, ++ FMTSTR_SUSPEND_MAC_FAIL_ID = 2, ++ FMTSTR_NO_PROGRESS_ID = 3, ++ FMTSTR_RFDISABLE_ID = 4, ++ FMTSTR_REG_PRINT_ID = 5, ++ FMTSTR_EXPTIME_ID = 6, ++ FMTSTR_JOIN_START_ID = 7, ++ FMTSTR_JOIN_COMPLETE_ID = 8, ++ FMTSTR_NO_NETWORKS_ID = 9, ++ FMTSTR_SECURITY_MISMATCH_ID = 10, ++ FMTSTR_RATE_MISMATCH_ID = 11, ++ FMTSTR_AP_PRUNED_ID = 12, ++ FMTSTR_KEY_INSERTED_ID = 13, ++ FMTSTR_DEAUTH_ID = 14, ++ FMTSTR_DISASSOC_ID = 15, ++ FMTSTR_LINK_UP_ID = 16, ++ FMTSTR_LINK_DOWN_ID = 17, ++ FMTSTR_RADIO_HW_OFF_ID = 18, ++ FMTSTR_RADIO_HW_ON_ID = 19, ++ FMTSTR_EVENT_DESC_ID = 20, ++ FMTSTR_PNP_SET_POWER_ID = 21, ++ FMTSTR_RADIO_SW_OFF_ID = 22, ++ FMTSTR_RADIO_SW_ON_ID = 23, ++ FMTSTR_PWD_MISMATCH_ID = 24, ++ FMTSTR_FATAL_ERROR_ID = 25, ++ FMTSTR_AUTH_FAIL_ID = 26, ++ FMTSTR_ASSOC_FAIL_ID = 27, ++ FMTSTR_IBSS_FAIL_ID = 28, ++ FMTSTR_EXTAP_FAIL_ID = 29, ++ FMTSTR_MAX_ID ++} log_fmtstr_id_t; ++ ++#ifdef DONGLEOVERLAYS ++typedef struct { ++ uint32 flags_idx; /* lower 8 bits: overlay index; upper 24 bits: flags */ ++ uint32 offset; /* offset into overlay region to write code */ ++ uint32 len; /* overlay code len */ ++ /* overlay code follows this struct */ ++} wl_ioctl_overlay_t; ++ ++#define OVERLAY_IDX_MASK 0x000000ff ++#define OVERLAY_IDX_SHIFT 0 ++#define OVERLAY_FLAGS_MASK 0xffffff00 ++#define OVERLAY_FLAGS_SHIFT 8 ++/* overlay written to device memory immediately after loading the base image */ ++#define OVERLAY_FLAG_POSTLOAD 0x100 ++/* defer overlay download until the device responds w/WLC_E_OVL_DOWNLOAD event */ ++#define OVERLAY_FLAG_DEFER_DL 0x200 ++/* overlay downloaded prior to the host going to sleep */ ++#define OVERLAY_FLAG_PRESLEEP 0x400 ++ ++#define OVERLAY_DOWNLOAD_CHUNKSIZE 1024 ++#endif /* DONGLEOVERLAYS */ ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* no default structure packing */ ++#include ++ ++/* require strict packing */ ++#include ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++ ++/* Structures and constants used for "vndr_ie" IOVar interface */ ++#define VNDR_IE_CMD_LEN 4 /* length of the set command string: ++ * "add", "del" (+ NUL) ++ */ ++ ++/* 802.11 Mgmt Packet flags */ ++#define VNDR_IE_BEACON_FLAG 0x1 ++#define VNDR_IE_PRBRSP_FLAG 0x2 ++#define VNDR_IE_ASSOCRSP_FLAG 0x4 ++#define VNDR_IE_AUTHRSP_FLAG 0x8 ++#define VNDR_IE_PRBREQ_FLAG 0x10 ++#define VNDR_IE_ASSOCREQ_FLAG 0x20 ++#define VNDR_IE_IWAPID_FLAG 0x40 /* vendor IE in IW advertisement protocol ID field */ ++#define VNDR_IE_CUSTOM_FLAG 0x100 /* allow custom IE id */ ++ ++#define VNDR_IE_INFO_HDR_LEN (sizeof(uint32)) ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ ++ vndr_ie_t vndr_ie_data; /* vendor IE data */ ++} BWL_POST_PACKED_STRUCT vndr_ie_info_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ int iecount; /* number of entries in the vndr_ie_list[] array */ ++ vndr_ie_info_t vndr_ie_list[1]; /* variable size list of vndr_ie_info_t structs */ ++} BWL_POST_PACKED_STRUCT vndr_ie_buf_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ char cmd[VNDR_IE_CMD_LEN]; /* vndr_ie IOVar set command : "add", "del" + NUL */ ++ vndr_ie_buf_t vndr_ie_buffer; /* buffer containing Vendor IE list information */ ++} BWL_POST_PACKED_STRUCT vndr_ie_setbuf_t; ++ ++/* tag_ID/length/value_buffer tuple */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 id; ++ uint8 len; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT tlv_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ ++ tlv_t ie_data; /* IE data */ ++} BWL_POST_PACKED_STRUCT ie_info_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ int iecount; /* number of entries in the ie_list[] array */ ++ ie_info_t ie_list[1]; /* variable size list of ie_info_t structs */ ++} BWL_POST_PACKED_STRUCT ie_buf_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ char cmd[VNDR_IE_CMD_LEN]; /* ie IOVar set command : "add" + NUL */ ++ ie_buf_t ie_buffer; /* buffer containing IE list information */ ++} BWL_POST_PACKED_STRUCT ie_setbuf_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ ++ uint8 id; /* IE type */ ++} BWL_POST_PACKED_STRUCT ie_getbuf_t; ++ ++/* structures used to define format of wps ie data from probe requests */ ++/* passed up to applications via iovar "prbreq_wpsie" */ ++typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_hdr { ++ struct ether_addr staAddr; ++ uint16 ieLen; ++} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_hdr_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_data { ++ sta_prbreq_wps_ie_hdr_t hdr; ++ uint8 ieData[1]; ++} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_data_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_list { ++ uint32 totLen; ++ uint8 ieDataList[1]; ++} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_list_t; ++ ++ ++#ifdef WLMEDIA_TXFAILEVENT ++typedef BWL_PRE_PACKED_STRUCT struct { ++ char dest[ETHER_ADDR_LEN]; /* destination MAC */ ++ uint8 prio; /* Packet Priority */ ++ uint8 flags; /* Flags */ ++ uint32 tsf_l; /* TSF timer low */ ++ uint32 tsf_h; /* TSF timer high */ ++ uint16 rates; /* Main Rates */ ++ uint16 txstatus; /* TX Status */ ++} BWL_POST_PACKED_STRUCT txfailinfo_t; ++#endif /* WLMEDIA_TXFAILEVENT */ ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++ ++/* no strict structure packing */ ++#include ++ ++#ifdef BCMWAPI_WAI ++#define IV_LEN 16 /* XXX, same as SMS4_WPI_PN_LEN */ ++struct wapi_sta_msg_t ++{ ++ uint16 msg_type; ++ uint16 datalen; ++ uint8 vap_mac[6]; ++ uint8 reserve_data1[2]; ++ uint8 sta_mac[6]; ++ uint8 reserve_data2[2]; ++ uint8 gsn[IV_LEN]; ++ uint8 wie[256]; ++}; ++#endif /* BCMWAPI_WAI */ ++ ++#ifndef LINUX_POSTMOGRIFY_REMOVAL ++/* Global ASSERT Logging */ ++#define ASSERTLOG_CUR_VER 0x0100 ++#define MAX_ASSRTSTR_LEN 64 ++ ++typedef struct assert_record { ++ uint32 time; ++ uint8 seq_num; ++ char str[MAX_ASSRTSTR_LEN]; ++} assert_record_t; ++ ++typedef struct assertlog_results { ++ uint16 version; ++ uint16 record_len; ++ uint32 num; ++ assert_record_t logs[1]; ++} assertlog_results_t; ++ ++#define LOGRRC_FIX_LEN 8 ++#define IOBUF_ALLOWED_NUM_OF_LOGREC(type, len) ((len - LOGRRC_FIX_LEN)/sizeof(type)) ++ ++ ++/* channel interference measurement (chanim) related defines */ ++ ++/* chanim mode */ ++#define CHANIM_DISABLE 0 /* disabled */ ++#define CHANIM_DETECT 1 /* detection only */ ++#define CHANIM_EXT 2 /* external state machine */ ++#define CHANIM_ACT 3 /* full internal state machine, detect + act */ ++#define CHANIM_MODE_MAX 4 ++ ++/* define for apcs reason code */ ++#define APCS_INIT 0 ++#define APCS_IOCTL 1 ++#define APCS_CHANIM 2 ++#define APCS_CSTIMER 3 ++#define APCS_BTA 4 ++ ++/* number of ACS record entries */ ++#define CHANIM_ACS_RECORD 10 ++ ++/* CHANIM */ ++#define CCASTATS_TXDUR 0 ++#define CCASTATS_INBSS 1 ++#define CCASTATS_OBSS 2 ++#define CCASTATS_NOCTG 3 ++#define CCASTATS_NOPKT 4 ++#define CCASTATS_DOZE 5 ++#define CCASTATS_TXOP 6 ++#define CCASTATS_GDTXDUR 7 ++#define CCASTATS_BDTXDUR 8 ++#define CCASTATS_MAX 9 ++ ++/* chanim acs record */ ++typedef struct { ++ bool valid; ++ uint8 trigger; ++ chanspec_t selected_chspc; ++ int8 bgnoise; ++ uint32 glitch_cnt; ++ uint8 ccastats; ++ uint timestamp; ++} chanim_acs_record_t; ++ ++typedef struct { ++ chanim_acs_record_t acs_record[CHANIM_ACS_RECORD]; ++ uint8 count; ++ uint timestamp; ++} wl_acs_record_t; ++ ++typedef struct chanim_stats { ++ uint32 glitchcnt; /* normalized as per second count */ ++ uint32 badplcp; /* normalized as per second count */ ++ uint8 ccastats[CCASTATS_MAX]; /* normalized as 0-255 */ ++ int8 bgnoise; /* background noise level (in dBm) */ ++ chanspec_t chanspec; ++ uint32 timestamp; ++} chanim_stats_t; ++ ++#define WL_CHANIM_STATS_VERSION 1 ++#define WL_CHANIM_COUNT_ALL 0xff ++#define WL_CHANIM_COUNT_ONE 0x1 ++ ++typedef struct { ++ uint32 buflen; ++ uint32 version; ++ uint32 count; ++ chanim_stats_t stats[1]; ++} wl_chanim_stats_t; ++ ++#define WL_CHANIM_STATS_FIXED_LEN OFFSETOF(wl_chanim_stats_t, stats) ++ ++/* Noise measurement metrics. */ ++#define NOISE_MEASURE_KNOISE 0x1 ++ ++/* scb probe parameter */ ++typedef struct { ++ uint32 scb_timeout; ++ uint32 scb_activity_time; ++ uint32 scb_max_probe; ++} wl_scb_probe_t; ++ ++/* ap tpc modes */ ++#define AP_TPC_OFF 0 ++#define AP_TPC_BSS_PWR 1 /* BSS power control */ ++#define AP_TPC_AP_PWR 2 /* AP power control */ ++#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ ++#define AP_TPC_MAX_LINK_MARGIN 127 ++ ++/* ap tpc modes */ ++#define AP_TPC_OFF 0 ++#define AP_TPC_BSS_PWR 1 /* BSS power control */ ++#define AP_TPC_AP_PWR 2 /* AP power control */ ++#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ ++#define AP_TPC_MAX_LINK_MARGIN 127 ++ ++/* structure/defines for selective mgmt frame (smf) stats support */ ++ ++#define SMFS_VERSION 1 ++/* selected mgmt frame (smf) stats element */ ++typedef struct wl_smfs_elem { ++ uint32 count; ++ uint16 code; /* SC or RC code */ ++} wl_smfs_elem_t; ++ ++typedef struct wl_smf_stats { ++ uint32 version; ++ uint16 length; /* reserved for future usage */ ++ uint8 type; ++ uint8 codetype; ++ uint32 ignored_cnt; ++ uint32 malformed_cnt; ++ uint32 count_total; /* count included the interested group */ ++ wl_smfs_elem_t elem[1]; ++} wl_smf_stats_t; ++ ++#define WL_SMFSTATS_FIXED_LEN OFFSETOF(wl_smf_stats_t, elem); ++ ++enum { ++ SMFS_CODETYPE_SC, ++ SMFS_CODETYPE_RC ++}; ++ ++/* reuse two number in the sc/rc space */ ++#define SMFS_CODE_MALFORMED 0xFFFE ++#define SMFS_CODE_IGNORED 0xFFFD ++ ++typedef enum smfs_type { ++ SMFS_TYPE_AUTH, ++ SMFS_TYPE_ASSOC, ++ SMFS_TYPE_REASSOC, ++ SMFS_TYPE_DISASSOC_TX, ++ SMFS_TYPE_DISASSOC_RX, ++ SMFS_TYPE_DEAUTH_TX, ++ SMFS_TYPE_DEAUTH_RX, ++ SMFS_TYPE_MAX ++} smfs_type_t; ++ ++#ifdef PHYMON ++ ++#define PHYMON_VERSION 1 ++ ++typedef struct wl_phycal_core_state { ++ /* Tx IQ/LO calibration coeffs */ ++ int16 tx_iqlocal_a; ++ int16 tx_iqlocal_b; ++ int8 tx_iqlocal_ci; ++ int8 tx_iqlocal_cq; ++ int8 tx_iqlocal_di; ++ int8 tx_iqlocal_dq; ++ int8 tx_iqlocal_ei; ++ int8 tx_iqlocal_eq; ++ int8 tx_iqlocal_fi; ++ int8 tx_iqlocal_fq; ++ ++ /* Rx IQ calibration coeffs */ ++ int16 rx_iqcal_a; ++ int16 rx_iqcal_b; ++ ++ uint8 tx_iqlocal_pwridx; /* Tx Power Index for Tx IQ/LO calibration */ ++ uint32 papd_epsilon_table[64]; /* PAPD epsilon table */ ++ int16 papd_epsilon_offset; /* PAPD epsilon offset */ ++ uint8 curr_tx_pwrindex; /* Tx power index */ ++ int8 idle_tssi; /* Idle TSSI */ ++ int8 est_tx_pwr; /* Estimated Tx Power (dB) */ ++ int8 est_rx_pwr; /* Estimated Rx Power (dB) from RSSI */ ++ uint16 rx_gaininfo; /* Rx gain applied on last Rx pkt */ ++ uint16 init_gaincode; /* initgain required for ACI */ ++ int8 estirr_tx; ++ int8 estirr_rx; ++ ++} wl_phycal_core_state_t; ++ ++typedef struct wl_phycal_state { ++ int version; ++ int8 num_phy_cores; /* number of cores */ ++ int8 curr_temperature; /* on-chip temperature sensor reading */ ++ chanspec_t chspec; /* channspec for this state */ ++ bool aci_state; /* ACI state: ON/OFF */ ++ uint16 crsminpower; /* crsminpower required for ACI */ ++ uint16 crsminpowerl; /* crsminpowerl required for ACI */ ++ uint16 crsminpoweru; /* crsminpoweru required for ACI */ ++ wl_phycal_core_state_t phycal_core[1]; ++} wl_phycal_state_t; ++ ++#define WL_PHYCAL_STAT_FIXED_LEN OFFSETOF(wl_phycal_state_t, phycal_core) ++#endif /* PHYMON */ ++ ++/* discovery state */ ++typedef struct wl_p2p_disc_st { ++ uint8 state; /* see state */ ++ chanspec_t chspec; /* valid in listen state */ ++ uint16 dwell; /* valid in listen state, in ms */ ++} wl_p2p_disc_st_t; ++ ++/* state */ ++#define WL_P2P_DISC_ST_SCAN 0 ++#define WL_P2P_DISC_ST_LISTEN 1 ++#define WL_P2P_DISC_ST_SEARCH 2 ++ ++/* scan request */ ++typedef struct wl_p2p_scan { ++ uint8 type; /* 'S' for WLC_SCAN, 'E' for "escan" */ ++ uint8 reserved[3]; ++ /* scan or escan parms... */ ++} wl_p2p_scan_t; ++ ++/* i/f request */ ++typedef struct wl_p2p_if { ++ struct ether_addr addr; ++ uint8 type; /* see i/f type */ ++ chanspec_t chspec; /* for p2p_ifadd GO */ ++} wl_p2p_if_t; ++ ++/* i/f type */ ++#define WL_P2P_IF_CLIENT 0 ++#define WL_P2P_IF_GO 1 ++#define WL_P2P_IF_DYNBCN_GO 2 ++#define WL_P2P_IF_DEV 3 ++ ++/* i/f query */ ++typedef struct wl_p2p_ifq { ++ uint bsscfgidx; ++ char ifname[BCM_MSG_IFNAME_MAX]; ++} wl_p2p_ifq_t; ++ ++/* OppPS & CTWindow */ ++typedef struct wl_p2p_ops { ++ uint8 ops; /* 0: disable 1: enable */ ++ uint8 ctw; /* >= 10 */ ++} wl_p2p_ops_t; ++ ++/* absence and presence request */ ++typedef struct wl_p2p_sched_desc { ++ uint32 start; ++ uint32 interval; ++ uint32 duration; ++ uint32 count; /* see count */ ++} wl_p2p_sched_desc_t; ++ ++/* count */ ++#define WL_P2P_SCHED_RSVD 0 ++#define WL_P2P_SCHED_REPEAT 255 /* anything > 255 will be treated as 255 */ ++ ++typedef struct wl_p2p_sched { ++ uint8 type; /* see schedule type */ ++ uint8 action; /* see schedule action */ ++ uint8 option; /* see schedule option */ ++ wl_p2p_sched_desc_t desc[1]; ++} wl_p2p_sched_t; ++#define WL_P2P_SCHED_FIXED_LEN 3 ++ ++/* schedule type */ ++#define WL_P2P_SCHED_TYPE_ABS 0 /* Scheduled Absence */ ++#define WL_P2P_SCHED_TYPE_REQ_ABS 1 /* Requested Absence */ ++ ++/* schedule action during absence periods (for WL_P2P_SCHED_ABS type) */ ++#define WL_P2P_SCHED_ACTION_NONE 0 /* no action */ ++#define WL_P2P_SCHED_ACTION_DOZE 1 /* doze */ ++/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ ++#define WL_P2P_SCHED_ACTION_GOOFF 2 /* turn off GO beacon/prbrsp functions */ ++/* schedule option - WL_P2P_SCHED_TYPE_XXX */ ++#define WL_P2P_SCHED_ACTION_RESET 255 /* reset */ ++ ++/* schedule option - WL_P2P_SCHED_TYPE_ABS */ ++#define WL_P2P_SCHED_OPTION_NORMAL 0 /* normal start/interval/duration/count */ ++#define WL_P2P_SCHED_OPTION_BCNPCT 1 /* percentage of beacon interval */ ++/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ ++#define WL_P2P_SCHED_OPTION_TSFOFS 2 /* normal start/internal/duration/count with ++ * start being an offset of the 'current' TSF ++ */ ++ ++/* feature flags */ ++#define WL_P2P_FEAT_GO_CSA (1 << 0) /* GO moves with the STA using CSA method */ ++#define WL_P2P_FEAT_GO_NOLEGACY (1 << 1) /* GO does not probe respond to non-p2p probe ++ * requests ++ */ ++#define WL_P2P_FEAT_RESTRICT_DEV_RESP (1 << 2) /* Restrict p2p dev interface from responding */ ++ ++#ifdef WLNIC ++/* nic_cnx iovar */ ++typedef struct wl_nic_cnx { ++ uint8 opcode; ++ struct ether_addr addr; ++ /* the following are valid for WL_NIC_CNX_CONN */ ++ uint8 SSID_len; ++ uint8 SSID[32]; ++ struct ether_addr abssid; ++ uint8 join_period; ++} wl_nic_cnx_t; ++ ++/* opcode */ ++#define WL_NIC_CNX_ADD 0 /* add NIC connection */ ++#define WL_NIC_CNX_DEL 1 /* delete NIC connection */ ++#define WL_NIC_CNX_IDX 2 /* query NIC connection index */ ++#define WL_NIC_CNX_CONN 3 /* join/create network */ ++#define WL_NIC_CNX_DIS 4 /* disconnect from network */ ++ ++/* nic_cfg iovar */ ++typedef struct wl_nic_cfg { ++ uint8 version; ++ uint8 beacon_mode; ++ uint16 beacon_interval; ++ uint8 diluted_beacon_period; ++ uint8 repeat_EQC; ++ uint8 scan_length; ++ uint8 scan_interval; ++ uint8 scan_probability; ++ uint8 awake_window_length; ++ int8 TSF_correction; ++ uint8 ASID; ++ uint8 channel_usage_mode; ++} wl_nic_cfg_t; ++ ++/* version */ ++#define WL_NIC_CFG_VER 1 ++ ++/* beacon_mode */ ++#define WL_NIC_BCN_NORM 0 ++#define WL_NIC_BCN_DILUTED 1 ++ ++/* channel_usage_mode */ ++#define WL_NIC_CHAN_STATIC 0 ++#define WL_NIC_CHAN_CYCLE 1 ++ ++/* nic_cfg iovar */ ++typedef struct wl_nic_frm { ++ uint8 type; ++ struct ether_addr da; ++ uint8 body[1]; ++} wl_nic_frm_t; ++ ++/* type */ ++#define WL_NIC_FRM_MYNET 1 ++#define WL_NIC_FRM_ACTION 2 ++ ++/* i/f query */ ++typedef struct wl_nic_ifq { ++ uint bsscfgidx; ++ char ifname[BCM_MSG_IFNAME_MAX]; ++} wl_nic_ifq_t; ++ ++/* data mode */ ++/* nic_dm iovar */ ++typedef struct wl_nic_dm { ++ uint8 enab; ++ chanspec_t chspec; ++} wl_nic_dm_t; ++#endif /* WLNIC */ ++ ++/* RFAWARE def */ ++#define BCM_ACTION_RFAWARE 0x77 ++#define BCM_ACTION_RFAWARE_DCS 0x01 ++ ++/* DCS reason code define */ ++#define BCM_DCS_IOVAR 0x1 ++#define BCM_DCS_UNKNOWN 0xFF ++ ++typedef struct wl_bcmdcs_data { ++ uint reason; ++ chanspec_t chspec; ++} wl_bcmdcs_data_t; ++ ++/* n-mode support capability */ ++/* 2x2 includes both 1x1 & 2x2 devices ++ * reserved #define 2 for future when we want to separate 1x1 & 2x2 and ++ * control it independently ++ */ ++#define WL_11N_2x2 1 ++#define WL_11N_3x3 3 ++#define WL_11N_4x4 4 ++ ++/* define 11n feature disable flags */ ++#define WLFEATURE_DISABLE_11N 0x00000001 ++#define WLFEATURE_DISABLE_11N_STBC_TX 0x00000002 ++#define WLFEATURE_DISABLE_11N_STBC_RX 0x00000004 ++#define WLFEATURE_DISABLE_11N_SGI_TX 0x00000008 ++#define WLFEATURE_DISABLE_11N_SGI_RX 0x00000010 ++#define WLFEATURE_DISABLE_11N_AMPDU_TX 0x00000020 ++#define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040 ++#define WLFEATURE_DISABLE_11N_GF 0x00000080 ++ ++/* Proxy STA modes */ ++#define PSTA_MODE_DISABLED 0 ++#define PSTA_MODE_PROXY 1 ++#define PSTA_MODE_REPEATER 2 ++ ++ ++/* NAT configuration */ ++typedef struct { ++ uint32 ipaddr; /* interface ip address */ ++ uint32 ipaddr_mask; /* interface ip address mask */ ++ uint32 ipaddr_gateway; /* gateway ip address */ ++ uint8 mac_gateway[6]; /* gateway mac address */ ++ uint32 ipaddr_dns; /* DNS server ip address, valid only for public if */ ++ uint8 mac_dns[6]; /* DNS server mac address, valid only for public if */ ++ uint8 GUID[38]; /* interface GUID */ ++} nat_if_info_t; ++ ++typedef struct { ++ uint op; /* operation code */ ++ bool pub_if; /* set for public if, clear for private if */ ++ nat_if_info_t if_info; /* interface info */ ++} nat_cfg_t; ++ ++/* op code in nat_cfg */ ++#define NAT_OP_ENABLE 1 /* enable NAT on given interface */ ++#define NAT_OP_DISABLE 2 /* disable NAT on given interface */ ++#define NAT_OP_DISABLE_ALL 3 /* disable NAT on all interfaces */ ++ ++/* NAT state */ ++#define NAT_STATE_ENABLED 1 /* NAT is enabled */ ++#define NAT_STATE_DISABLED 2 /* NAT is disabled */ ++ ++typedef struct { ++ int state; /* NAT state returned */ ++} nat_state_t; ++ ++#ifdef PROP_TXSTATUS ++/* Bit definitions for tlv iovar */ ++/* ++ * enable RSSI signals: ++ * WLFC_CTL_TYPE_RSSI ++ */ ++#define WLFC_FLAGS_RSSI_SIGNALS 0x0001 ++ ++/* enable (if/mac_open, if/mac_close,, mac_add, mac_del) signals: ++ * ++ * WLFC_CTL_TYPE_MAC_OPEN ++ * WLFC_CTL_TYPE_MAC_CLOSE ++ * ++ * WLFC_CTL_TYPE_INTERFACE_OPEN ++ * WLFC_CTL_TYPE_INTERFACE_CLOSE ++ * ++ * WLFC_CTL_TYPE_MACDESC_ADD ++ * WLFC_CTL_TYPE_MACDESC_DEL ++ * ++ */ ++#define WLFC_FLAGS_XONXOFF_SIGNALS 0x0002 ++ ++/* enable (status, fifo_credit, mac_credit) signals ++ * WLFC_CTL_TYPE_MAC_REQUEST_CREDIT ++ * WLFC_CTL_TYPE_TXSTATUS ++ * WLFC_CTL_TYPE_FIFO_CREDITBACK ++ */ ++#define WLFC_FLAGS_CREDIT_STATUS_SIGNALS 0x0004 ++ ++#define WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008 ++#define WLFC_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010 ++#define WLFC_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020 ++#define WLFC_FLAGS_HOST_RXRERODER_ACTIVE 0x0040 ++#endif /* PROP_TXSTATUS */ ++ ++#define BTA_STATE_LOG_SZ 64 ++ ++/* BTAMP Statemachine states */ ++enum { ++ HCIReset = 1, ++ HCIReadLocalAMPInfo, ++ HCIReadLocalAMPASSOC, ++ HCIWriteRemoteAMPASSOC, ++ HCICreatePhysicalLink, ++ HCIAcceptPhysicalLinkRequest, ++ HCIDisconnectPhysicalLink, ++ HCICreateLogicalLink, ++ HCIAcceptLogicalLink, ++ HCIDisconnectLogicalLink, ++ HCILogicalLinkCancel, ++ HCIAmpStateChange, ++ HCIWriteLogicalLinkAcceptTimeout ++}; ++ ++typedef struct flush_txfifo { ++ uint32 txfifobmp; ++ uint32 hwtxfifoflush; ++ struct ether_addr ea; ++} flush_txfifo_t; ++ ++#define CHANNEL_5G_LOW_START 36 /* 5G low (36..48) CDD enable/disable bit mask */ ++#define CHANNEL_5G_MID_START 52 /* 5G mid (52..64) CDD enable/disable bit mask */ ++#define CHANNEL_5G_HIGH_START 100 /* 5G high (100..140) CDD enable/disable bit mask */ ++#define CHANNEL_5G_UPPER_START 149 /* 5G upper (149..161) CDD enable/disable bit mask */ ++ ++enum { ++ SPATIAL_MODE_2G_IDX = 0, ++ SPATIAL_MODE_5G_LOW_IDX, ++ SPATIAL_MODE_5G_MID_IDX, ++ SPATIAL_MODE_5G_HIGH_IDX, ++ SPATIAL_MODE_5G_UPPER_IDX, ++ SPATIAL_MODE_MAX_IDX ++}; ++ ++/* IOVAR "mempool" parameter. Used to retrieve a list of memory pool statistics. */ ++typedef struct wl_mempool_stats { ++ int num; /* Number of memory pools */ ++ bcm_mp_stats_t s[1]; /* Variable array of memory pool stats. */ ++} wl_mempool_stats_t; ++ ++ ++/* D0 Coalescing */ ++#define IPV4_ARP_FILTER 0x0001 ++#define IPV4_NETBT_FILTER 0x0002 ++#define IPV4_LLMNR_FILTER 0x0004 ++#define IPV4_SSDP_FILTER 0x0008 ++#define IPV4_WSD_FILTER 0x0010 ++#define IPV6_NETBT_FILTER 0x0200 ++#define IPV6_LLMNR_FILTER 0x0400 ++#define IPV6_SSDP_FILTER 0x0800 ++#define IPV6_WSD_FILTER 0x1000 ++ ++/* Network Offload Engine */ ++#define NWOE_OL_ENABLE 0x00000001 ++ ++typedef struct { ++ uint32 ipaddr; ++ uint32 ipaddr_netmask; ++ uint32 ipaddr_gateway; ++} nwoe_ifconfig_t; ++ ++/* ++ * Traffic management structures/defines. ++ */ ++ ++/* Traffic management bandwidth parameters */ ++#define TRF_MGMT_MAX_PRIORITIES 3 ++ ++#define TRF_MGMT_FLAG_ADD_DSCP 0x0001 /* Add DSCP to IP TOS field */ ++#define TRF_MGMT_FLAG_DISABLE_SHAPING 0x0002 /* Only support traffic clasification */ ++#define TRF_MGMT_FLAG_DISABLE_PRIORITY_TAGGING 0x0004 /* Don't override packet's priority */ ++ ++/* Traffic management priority classes */ ++typedef enum trf_mgmt_priority_class { ++ trf_mgmt_priority_low = 0, /* Maps to 802.1p BO */ ++ trf_mgmt_priority_medium = 1, /* Maps to 802.1p BE */ ++ trf_mgmt_priority_high = 2, /* Maps to 802.1p VI */ ++ trf_mgmt_priority_invalid = (trf_mgmt_priority_high + 1) ++} trf_mgmt_priority_class_t; ++ ++/* Traffic management configuration parameters */ ++typedef struct trf_mgmt_config { ++ uint32 trf_mgmt_enabled; /* 0 - disabled, 1 - enabled */ ++ uint32 flags; /* See TRF_MGMT_FLAG_xxx defines */ ++ uint32 host_ip_addr; /* My IP address to determine subnet */ ++ uint32 host_subnet_mask; /* My subnet mask */ ++ uint32 downlink_bandwidth; /* In units of kbps */ ++ uint32 uplink_bandwidth; /* In units of kbps */ ++ uint32 min_tx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /* Minimum guaranteed tx bandwidth */ ++ uint32 min_rx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /* Minimum guaranteed rx bandwidth */ ++} trf_mgmt_config_t; ++ ++/* Traffic management filter */ ++typedef struct trf_mgmt_filter { ++ struct ether_addr dst_ether_addr; /* His L2 address */ ++ uint32 dst_ip_addr; /* His IP address */ ++ uint16 dst_port; /* His L4 port */ ++ uint16 src_port; /* My L4 port */ ++ uint16 prot; /* L4 protocol (only TCP or UDP) */ ++ uint16 flags; /* TBD. For now, this must be zero. */ ++ trf_mgmt_priority_class_t priority; /* Priority for filtered packets */ ++} trf_mgmt_filter_t; ++ ++/* Traffic management filter list (variable length) */ ++typedef struct trf_mgmt_filter_list { ++ uint32 num_filters; ++ trf_mgmt_filter_t filter[1]; ++} trf_mgmt_filter_list_t; ++ ++/* Traffic management global info used for all queues */ ++typedef struct trf_mgmt_global_info { ++ uint32 maximum_bytes_per_second; ++ uint32 maximum_bytes_per_sampling_period; ++ uint32 total_bytes_consumed_per_second; ++ uint32 total_bytes_consumed_per_sampling_period; ++ uint32 total_unused_bytes_per_sampling_period; ++} trf_mgmt_global_info_t; ++ ++/* Traffic management shaping info per priority queue */ ++typedef struct trf_mgmt_shaping_info { ++ uint32 gauranteed_bandwidth_percentage; ++ uint32 guaranteed_bytes_per_second; ++ uint32 guaranteed_bytes_per_sampling_period; ++ uint32 num_bytes_produced_per_second; ++ uint32 num_bytes_consumed_per_second; ++ uint32 num_queued_packets; /* Number of packets in queue */ ++ uint32 num_queued_bytes; /* Number of bytes in queue */ ++} trf_mgmt_shaping_info_t; ++ ++/* Traffic management shaping info array */ ++typedef struct trf_mgmt_shaping_info_array { ++ trf_mgmt_global_info_t tx_global_shaping_info; ++ trf_mgmt_shaping_info_t tx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; ++ trf_mgmt_global_info_t rx_global_shaping_info; ++ trf_mgmt_shaping_info_t rx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; ++} trf_mgmt_shaping_info_array_t; ++ ++ ++/* Traffic management statistical counters */ ++typedef struct trf_mgmt_stats { ++ uint32 num_processed_packets; /* Number of packets processed */ ++ uint32 num_processed_bytes; /* Number of bytes processed */ ++ uint32 num_discarded_packets; /* Number of packets discarded from queue */ ++} trf_mgmt_stats_t; ++ ++/* Traffic management statisics array */ ++typedef struct trf_mgmt_stats_array { ++ trf_mgmt_stats_t tx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; ++ trf_mgmt_stats_t rx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; ++} trf_mgmt_stats_array_t; ++ ++typedef struct powersel_params { ++ /* LPC Params exposed via IOVAR */ ++ int32 tp_ratio_thresh; /* Throughput ratio threshold */ ++ uint8 rate_stab_thresh; /* Thresh for rate stability based on nupd */ ++ uint8 pwr_stab_thresh; /* Number of successes before power step down */ ++ uint8 pwr_sel_exp_time; /* Time lapse for expiry of database */ ++} powersel_params_t; ++ ++#endif /* LINUX_POSTMOGRIFY_REMOVAL */ ++#endif /* _wlioctl_h_ */ +diff --git a/drivers/net/wireless/ap6211/linux_osl.c b/drivers/net/wireless/ap6211/linux_osl.c +new file mode 100755 +index 0000000..d74eee3 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/linux_osl.c +@@ -0,0 +1,1138 @@ ++/* ++ * Linux OS Independent Layer ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: linux_osl.c 373382 2012-12-07 07:59:52Z $ ++ */ ++ ++#define LINUX_PORT ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++ ++#define PCI_CFG_RETRY 10 ++ ++#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognize osh */ ++#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ ++ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++#define DHD_SKB_HDRSIZE 336 ++#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE) ++#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE) ++#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE) ++ ++#define STATIC_BUF_MAX_NUM 16 ++#define STATIC_BUF_SIZE (PAGE_SIZE*2) ++#define STATIC_BUF_TOTAL_LEN (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE) ++ ++typedef struct bcm_static_buf { ++ struct semaphore static_sem; ++ unsigned char *buf_ptr; ++ unsigned char buf_use[STATIC_BUF_MAX_NUM]; ++} bcm_static_buf_t; ++ ++static bcm_static_buf_t *bcm_static_buf = 0; ++ ++#define STATIC_PKT_MAX_NUM 8 ++#if defined(ENHANCED_STATIC_BUF) ++#define STATIC_PKT_4PAGE_NUM 1 ++#define DHD_SKB_MAX_BUFSIZE DHD_SKB_4PAGE_BUFSIZE ++#else ++#define STATIC_PKT_4PAGE_NUM 0 ++#define DHD_SKB_MAX_BUFSIZE DHD_SKB_2PAGE_BUFSIZE ++#endif /* ENHANCED_STATIC_BUF */ ++ ++typedef struct bcm_static_pkt { ++ struct sk_buff *skb_4k[STATIC_PKT_MAX_NUM]; ++ struct sk_buff *skb_8k[STATIC_PKT_MAX_NUM]; ++#ifdef ENHANCED_STATIC_BUF ++ struct sk_buff *skb_16k; ++#endif ++ struct semaphore osl_pkt_sem; ++ unsigned char pkt_use[STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM]; ++} bcm_static_pkt_t; ++ ++static bcm_static_pkt_t *bcm_static_skb = 0; ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++typedef struct bcm_mem_link { ++ struct bcm_mem_link *prev; ++ struct bcm_mem_link *next; ++ uint size; ++ int line; ++ void *osh; ++ char file[BCM_MEM_FILENAME_LEN]; ++} bcm_mem_link_t; ++ ++struct osl_info { ++ osl_pubinfo_t pub; ++#ifdef CTFPOOL ++ ctfpool_t *ctfpool; ++#endif /* CTFPOOL */ ++ uint magic; ++ void *pdev; ++ atomic_t malloced; ++ uint failed; ++ uint bustype; ++ bcm_mem_link_t *dbgmem_list; ++ spinlock_t dbgmem_lock; ++ spinlock_t pktalloc_lock; ++}; ++ ++/* PCMCIA attribute space access macros */ ++ ++/* Global ASSERT type flag */ ++uint32 g_assert_type = FALSE; ++ ++static int16 linuxbcmerrormap[] = ++{ 0, /* 0 */ ++ -EINVAL, /* BCME_ERROR */ ++ -EINVAL, /* BCME_BADARG */ ++ -EINVAL, /* BCME_BADOPTION */ ++ -EINVAL, /* BCME_NOTUP */ ++ -EINVAL, /* BCME_NOTDOWN */ ++ -EINVAL, /* BCME_NOTAP */ ++ -EINVAL, /* BCME_NOTSTA */ ++ -EINVAL, /* BCME_BADKEYIDX */ ++ -EINVAL, /* BCME_RADIOOFF */ ++ -EINVAL, /* BCME_NOTBANDLOCKED */ ++ -EINVAL, /* BCME_NOCLK */ ++ -EINVAL, /* BCME_BADRATESET */ ++ -EINVAL, /* BCME_BADBAND */ ++ -E2BIG, /* BCME_BUFTOOSHORT */ ++ -E2BIG, /* BCME_BUFTOOLONG */ ++ -EBUSY, /* BCME_BUSY */ ++ -EINVAL, /* BCME_NOTASSOCIATED */ ++ -EINVAL, /* BCME_BADSSIDLEN */ ++ -EINVAL, /* BCME_OUTOFRANGECHAN */ ++ -EINVAL, /* BCME_BADCHAN */ ++ -EFAULT, /* BCME_BADADDR */ ++ -ENOMEM, /* BCME_NORESOURCE */ ++ -EOPNOTSUPP, /* BCME_UNSUPPORTED */ ++ -EMSGSIZE, /* BCME_BADLENGTH */ ++ -EINVAL, /* BCME_NOTREADY */ ++ -EPERM, /* BCME_EPERM */ ++ -ENOMEM, /* BCME_NOMEM */ ++ -EINVAL, /* BCME_ASSOCIATED */ ++ -ERANGE, /* BCME_RANGE */ ++ -EINVAL, /* BCME_NOTFOUND */ ++ -EINVAL, /* BCME_WME_NOT_ENABLED */ ++ -EINVAL, /* BCME_TSPEC_NOTFOUND */ ++ -EINVAL, /* BCME_ACM_NOTSUPPORTED */ ++ -EINVAL, /* BCME_NOT_WME_ASSOCIATION */ ++ -EIO, /* BCME_SDIO_ERROR */ ++ -ENODEV, /* BCME_DONGLE_DOWN */ ++ -EINVAL, /* BCME_VERSION */ ++ -EIO, /* BCME_TXFAIL */ ++ -EIO, /* BCME_RXFAIL */ ++ -ENODEV, /* BCME_NODEVICE */ ++ -EINVAL, /* BCME_NMODE_DISABLED */ ++ -ENODATA, /* BCME_NONRESIDENT */ ++ ++/* When an new error code is added to bcmutils.h, add os ++ * specific error translation here as well ++ */ ++/* check if BCME_LAST changed since the last time this function was updated */ ++#if BCME_LAST != -42 ++#error "You need to add a OS error translation in the linuxbcmerrormap \ ++ for new error code defined in bcmutils.h" ++#endif ++}; ++ ++/* translate bcmerrors into linux errors */ ++int ++osl_error(int bcmerror) ++{ ++ if (bcmerror > 0) ++ bcmerror = 0; ++ else if (bcmerror < BCME_LAST) ++ bcmerror = BCME_ERROR; ++ ++ /* Array bounds covered by ASSERT in osl_attach */ ++ return linuxbcmerrormap[-bcmerror]; ++} ++ ++extern uint8* dhd_os_prealloc(void *osh, int section, int size); ++ ++osl_t * ++osl_attach(void *pdev, uint bustype, bool pkttag) ++{ ++ osl_t *osh; ++ ++ if (!(osh = kmalloc(sizeof(osl_t), GFP_ATOMIC))) ++ return osh; ++ ++ ASSERT(osh); ++ ++ bzero(osh, sizeof(osl_t)); ++ ++ /* Check that error map has the right number of entries in it */ ++ ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1)); ++ ++ osh->magic = OS_HANDLE_MAGIC; ++ atomic_set(&osh->malloced, 0); ++ osh->failed = 0; ++ osh->dbgmem_list = NULL; ++ spin_lock_init(&(osh->dbgmem_lock)); ++ osh->pdev = pdev; ++ osh->pub.pkttag = pkttag; ++ osh->bustype = bustype; ++ ++ switch (bustype) { ++ case PCI_BUS: ++ case SI_BUS: ++ case PCMCIA_BUS: ++ osh->pub.mmbus = TRUE; ++ break; ++ case JTAG_BUS: ++ case SDIO_BUS: ++ case USB_BUS: ++ case SPI_BUS: ++ case RPC_BUS: ++ osh->pub.mmbus = FALSE; ++ break; ++ default: ++ ASSERT(FALSE); ++ break; ++ } ++ ++#if defined(CONFIG_DHD_USE_STATIC_BUF) ++ if (!bcm_static_buf) { ++ if (!(bcm_static_buf = (bcm_static_buf_t *)dhd_os_prealloc(osh, 3, STATIC_BUF_SIZE+ ++ STATIC_BUF_TOTAL_LEN))) { ++ AP6211_DEBUG("can not alloc static buf!\n"); ++ } ++ else ++ AP6211_DEBUG("alloc static buf at %x!\n", (unsigned int)bcm_static_buf); ++ ++ ++ sema_init(&bcm_static_buf->static_sem, 1); ++ ++ bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE; ++ } ++ ++ if (!bcm_static_skb) { ++ int i; ++ void *skb_buff_ptr = 0; ++ bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); ++ skb_buff_ptr = dhd_os_prealloc(osh, 4, 0); ++ ++ bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *)* ++ (STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM)); ++ for (i = 0; i < (STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM); i++) ++ bcm_static_skb->pkt_use[i] = 0; ++ ++ sema_init(&bcm_static_skb->osl_pkt_sem, 1); ++ } ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++ spin_lock_init(&(osh->pktalloc_lock)); ++ ++ return osh; ++} ++ ++void ++osl_detach(osl_t *osh) ++{ ++ if (osh == NULL) ++ return; ++ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ if (bcm_static_buf) { ++ bcm_static_buf = 0; ++ } ++ if (bcm_static_skb) { ++ bcm_static_skb = 0; ++ } ++#endif ++ ++ ASSERT(osh->magic == OS_HANDLE_MAGIC); ++ kfree(osh); ++} ++ ++static struct sk_buff *osl_alloc_skb(unsigned int len) ++{ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) ++ return __dev_alloc_skb(len, GFP_ATOMIC); ++#else ++ return dev_alloc_skb(len); ++#endif ++} ++ ++#ifdef CTFPOOL ++ ++#ifdef CTFPOOL_SPINLOCK ++#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_irqsave(&(ctfpool)->lock, flags) ++#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_irqrestore(&(ctfpool)->lock, flags) ++#else ++#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_bh(&(ctfpool)->lock) ++#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_bh(&(ctfpool)->lock) ++#endif /* CTFPOOL_SPINLOCK */ ++/* ++ * Allocate and add an object to packet pool. ++ */ ++void * ++osl_ctfpool_add(osl_t *osh) ++{ ++ struct sk_buff *skb; ++#ifdef CTFPOOL_SPINLOCK ++ unsigned long flags; ++#endif /* CTFPOOL_SPINLOCK */ ++ ++ if ((osh == NULL) || (osh->ctfpool == NULL)) ++ return NULL; ++ ++ CTFPOOL_LOCK(osh->ctfpool, flags); ++ ASSERT(osh->ctfpool->curr_obj <= osh->ctfpool->max_obj); ++ ++ /* No need to allocate more objects */ ++ if (osh->ctfpool->curr_obj == osh->ctfpool->max_obj) { ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ return NULL; ++ } ++ ++ /* Allocate a new skb and add it to the ctfpool */ ++ skb = osl_alloc_skb(osh->ctfpool->obj_size); ++ if (skb == NULL) { ++ AP6211_DEBUG("%s: skb alloc of len %d failed\n", __FUNCTION__, ++ osh->ctfpool->obj_size); ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ return NULL; ++ } ++ ++ /* Add to ctfpool */ ++ skb->next = (struct sk_buff *)osh->ctfpool->head; ++ osh->ctfpool->head = skb; ++ osh->ctfpool->fast_frees++; ++ osh->ctfpool->curr_obj++; ++ ++ /* Hijack a skb member to store ptr to ctfpool */ ++ CTFPOOLPTR(osh, skb) = (void *)osh->ctfpool; ++ ++ /* Use bit flag to indicate skb from fast ctfpool */ ++ PKTFAST(osh, skb) = FASTBUF; ++ ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ ++ return skb; ++} ++ ++/* ++ * Add new objects to the pool. ++ */ ++void ++osl_ctfpool_replenish(osl_t *osh, uint thresh) ++{ ++ if ((osh == NULL) || (osh->ctfpool == NULL)) ++ return; ++ ++ /* Do nothing if no refills are required */ ++ while ((osh->ctfpool->refills > 0) && (thresh--)) { ++ osl_ctfpool_add(osh); ++ osh->ctfpool->refills--; ++ } ++} ++ ++/* ++ * Initialize the packet pool with specified number of objects. ++ */ ++int32 ++osl_ctfpool_init(osl_t *osh, uint numobj, uint size) ++{ ++ osh->ctfpool = kmalloc(sizeof(ctfpool_t), GFP_ATOMIC); ++ ASSERT(osh->ctfpool); ++ bzero(osh->ctfpool, sizeof(ctfpool_t)); ++ ++ osh->ctfpool->max_obj = numobj; ++ osh->ctfpool->obj_size = size; ++ ++ spin_lock_init(&osh->ctfpool->lock); ++ ++ while (numobj--) { ++ if (!osl_ctfpool_add(osh)) ++ return -1; ++ osh->ctfpool->fast_frees--; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Cleanup the packet pool objects. ++ */ ++void ++osl_ctfpool_cleanup(osl_t *osh) ++{ ++ struct sk_buff *skb, *nskb; ++#ifdef CTFPOOL_SPINLOCK ++ unsigned long flags; ++#endif /* CTFPOOL_SPINLOCK */ ++ ++ if ((osh == NULL) || (osh->ctfpool == NULL)) ++ return; ++ ++ CTFPOOL_LOCK(osh->ctfpool, flags); ++ ++ skb = osh->ctfpool->head; ++ ++ while (skb != NULL) { ++ nskb = skb->next; ++ dev_kfree_skb(skb); ++ skb = nskb; ++ osh->ctfpool->curr_obj--; ++ } ++ ++ ASSERT(osh->ctfpool->curr_obj == 0); ++ osh->ctfpool->head = NULL; ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ ++ kfree(osh->ctfpool); ++ osh->ctfpool = NULL; ++} ++ ++void ++osl_ctfpool_stats(osl_t *osh, void *b) ++{ ++ struct bcmstrbuf *bb; ++ ++ if ((osh == NULL) || (osh->ctfpool == NULL)) ++ return; ++ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ if (bcm_static_buf) { ++ bcm_static_buf = 0; ++ } ++ if (bcm_static_skb) { ++ bcm_static_skb = 0; ++ } ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++ bb = b; ++ ++ ASSERT((osh != NULL) && (bb != NULL)); ++ ++ bcm_bprintf(bb, "max_obj %d obj_size %d curr_obj %d refills %d\n", ++ osh->ctfpool->max_obj, osh->ctfpool->obj_size, ++ osh->ctfpool->curr_obj, osh->ctfpool->refills); ++ bcm_bprintf(bb, "fast_allocs %d fast_frees %d slow_allocs %d\n", ++ osh->ctfpool->fast_allocs, osh->ctfpool->fast_frees, ++ osh->ctfpool->slow_allocs); ++} ++ ++static inline struct sk_buff * ++osl_pktfastget(osl_t *osh, uint len) ++{ ++ struct sk_buff *skb; ++#ifdef CTFPOOL_SPINLOCK ++ unsigned long flags; ++#endif /* CTFPOOL_SPINLOCK */ ++ ++ /* Try to do fast allocate. Return null if ctfpool is not in use ++ * or if there are no items in the ctfpool. ++ */ ++ if (osh->ctfpool == NULL) ++ return NULL; ++ ++ CTFPOOL_LOCK(osh->ctfpool, flags); ++ if (osh->ctfpool->head == NULL) { ++ ASSERT(osh->ctfpool->curr_obj == 0); ++ osh->ctfpool->slow_allocs++; ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ return NULL; ++ } ++ ++ ASSERT(len <= osh->ctfpool->obj_size); ++ ++ /* Get an object from ctfpool */ ++ skb = (struct sk_buff *)osh->ctfpool->head; ++ osh->ctfpool->head = (void *)skb->next; ++ ++ osh->ctfpool->fast_allocs++; ++ osh->ctfpool->curr_obj--; ++ ASSERT(CTFPOOLHEAD(osh, skb) == (struct sock *)osh->ctfpool->head); ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ ++ /* Init skb struct */ ++ skb->next = skb->prev = NULL; ++ skb->data = skb->head + 16; ++ skb->tail = skb->head + 16; ++ ++ skb->len = 0; ++ skb->cloned = 0; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) ++ skb->list = NULL; ++#endif ++ atomic_set(&skb->users, 1); ++ ++ return skb; ++} ++#endif /* CTFPOOL */ ++/* Convert a driver packet to native(OS) packet ++ * In the process, packettag is zeroed out before sending up ++ * IP code depends on skb->cb to be setup correctly with various options ++ * In our case, that means it should be 0 ++ */ ++struct sk_buff * BCMFASTPATH ++osl_pkt_tonative(osl_t *osh, void *pkt) ++{ ++#ifndef WL_UMK ++ struct sk_buff *nskb; ++ unsigned long flags; ++#endif ++ ++ if (osh->pub.pkttag) ++ bzero((void*)((struct sk_buff *)pkt)->cb, OSL_PKTTAG_SZ); ++ ++#ifndef WL_UMK ++ /* Decrement the packet counter */ ++ for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { ++ spin_lock_irqsave(&osh->pktalloc_lock, flags); ++ osh->pub.pktalloced--; ++ spin_unlock_irqrestore(&osh->pktalloc_lock, flags); ++ } ++#endif /* WL_UMK */ ++ return (struct sk_buff *)pkt; ++} ++ ++/* Convert a native(OS) packet to driver packet. ++ * In the process, native packet is destroyed, there is no copying ++ * Also, a packettag is zeroed out ++ */ ++void * BCMFASTPATH ++osl_pkt_frmnative(osl_t *osh, void *pkt) ++{ ++#ifndef WL_UMK ++ struct sk_buff *nskb; ++ unsigned long flags; ++#endif ++ ++ if (osh->pub.pkttag) ++ bzero((void*)((struct sk_buff *)pkt)->cb, OSL_PKTTAG_SZ); ++ ++#ifndef WL_UMK ++ /* Increment the packet counter */ ++ for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { ++ spin_lock_irqsave(&osh->pktalloc_lock, flags); ++ osh->pub.pktalloced++; ++ spin_unlock_irqrestore(&osh->pktalloc_lock, flags); ++ } ++#endif /* WL_UMK */ ++ return (void *)pkt; ++} ++ ++/* Return a new packet. zero out pkttag */ ++void * BCMFASTPATH ++osl_pktget(osl_t *osh, uint len) ++{ ++ struct sk_buff *skb; ++ unsigned long flags; ++ ++#ifdef CTFPOOL ++ /* Allocate from local pool */ ++ skb = osl_pktfastget(osh, len); ++ if ((skb != NULL) || ((skb = osl_alloc_skb(len)) != NULL)) { ++#else /* CTFPOOL */ ++ if ((skb = osl_alloc_skb(len))) { ++#endif /* CTFPOOL */ ++ skb_put(skb, len); ++ skb->priority = 0; ++ ++ ++ spin_lock_irqsave(&osh->pktalloc_lock, flags); ++ osh->pub.pktalloced++; ++ spin_unlock_irqrestore(&osh->pktalloc_lock, flags); ++ } ++ ++ return ((void*) skb); ++} ++ ++#ifdef CTFPOOL ++static inline void ++osl_pktfastfree(osl_t *osh, struct sk_buff *skb) ++{ ++ ctfpool_t *ctfpool; ++#ifdef CTFPOOL_SPINLOCK ++ unsigned long flags; ++#endif /* CTFPOOL_SPINLOCK */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) ++ skb->tstamp.tv.sec = 0; ++#else ++ skb->stamp.tv_sec = 0; ++#endif ++ ++ /* We only need to init the fields that we change */ ++ skb->dev = NULL; ++ skb->dst = NULL; ++ memset(skb->cb, 0, sizeof(skb->cb)); ++ skb->ip_summed = 0; ++ skb->destructor = NULL; ++ ++ ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); ++ ASSERT(ctfpool != NULL); ++ ++ /* Add object to the ctfpool */ ++ CTFPOOL_LOCK(ctfpool, flags); ++ skb->next = (struct sk_buff *)ctfpool->head; ++ ctfpool->head = (void *)skb; ++ ++ ctfpool->fast_frees++; ++ ctfpool->curr_obj++; ++ ++ ASSERT(ctfpool->curr_obj <= ctfpool->max_obj); ++ CTFPOOL_UNLOCK(ctfpool, flags); ++} ++#endif /* CTFPOOL */ ++ ++/* Free the driver packet. Free the tag if present */ ++void BCMFASTPATH ++osl_pktfree(osl_t *osh, void *p, bool send) ++{ ++ struct sk_buff *skb, *nskb; ++ unsigned long flags; ++ ++ skb = (struct sk_buff*) p; ++ ++ if (send && osh->pub.tx_fn) ++ osh->pub.tx_fn(osh->pub.tx_ctx, p, 0); ++ ++ PKTDBG_TRACE(osh, (void *) skb, PKTLIST_PKTFREE); ++ ++ /* perversion: we use skb->next to chain multi-skb packets */ ++ while (skb) { ++ nskb = skb->next; ++ skb->next = NULL; ++ ++ ++ ++#ifdef CTFPOOL ++ if ((PKTISFAST(osh, skb)) && (atomic_read(&skb->users) == 1)) ++ osl_pktfastfree(osh, skb); ++ else { ++#else /* CTFPOOL */ ++ { ++#endif /* CTFPOOL */ ++ ++ if (skb->destructor) ++ /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if ++ * destructor exists ++ */ ++ dev_kfree_skb_any(skb); ++ else ++ /* can free immediately (even in_irq()) if destructor ++ * does not exist ++ */ ++ dev_kfree_skb(skb); ++ } ++ spin_lock_irqsave(&osh->pktalloc_lock, flags); ++ osh->pub.pktalloced--; ++ spin_unlock_irqrestore(&osh->pktalloc_lock, flags); ++ skb = nskb; ++ } ++} ++ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++void* ++osl_pktget_static(osl_t *osh, uint len) ++{ ++ int i = 0; ++ struct sk_buff *skb; ++ ++ ++ if (len > DHD_SKB_MAX_BUFSIZE) { ++ AP6211_DEBUG("osl_pktget_static: Do we really need this big skb??" ++ " len=%d\n", len); ++ return osl_pktget(osh, len); ++ } ++ ++ down(&bcm_static_skb->osl_pkt_sem); ++ ++ if (len <= DHD_SKB_1PAGE_BUFSIZE) { ++ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { ++ if (bcm_static_skb->pkt_use[i] == 0) ++ break; ++ } ++ ++ if (i != STATIC_PKT_MAX_NUM) { ++ bcm_static_skb->pkt_use[i] = 1; ++ ++ skb = bcm_static_skb->skb_4k[i]; ++ skb->tail = skb->data + len; ++ skb->len = len; ++ ++ up(&bcm_static_skb->osl_pkt_sem); ++ return skb; ++ } ++ } ++ ++ if (len <= DHD_SKB_2PAGE_BUFSIZE) { ++ ++ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { ++ if (bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] ++ == 0) ++ break; ++ } ++ ++ if (i != STATIC_PKT_MAX_NUM) { ++ bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 1; ++ skb = bcm_static_skb->skb_8k[i]; ++ skb->tail = skb->data + len; ++ skb->len = len; ++ ++ up(&bcm_static_skb->osl_pkt_sem); ++ return skb; ++ } ++ } ++ ++#if defined(ENHANCED_STATIC_BUF) ++ if (bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] == 0) { ++ bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] = 1; ++ ++ skb = bcm_static_skb->skb_16k; ++ skb->tail = skb->data + len; ++ skb->len = len; ++ ++ up(&bcm_static_skb->osl_pkt_sem); ++ return skb; ++ } ++#endif ++ ++ up(&bcm_static_skb->osl_pkt_sem); ++ AP6211_DEBUG("osl_pktget_static: all static pkt in use!\n"); ++ return osl_pktget(osh, len); ++} ++ ++void ++osl_pktfree_static(osl_t *osh, void *p, bool send) ++{ ++ int i; ++ if (!bcm_static_skb) { ++ osl_pktfree(osh, p, send); ++ return; ++ } ++ ++ down(&bcm_static_skb->osl_pkt_sem); ++ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { ++ if (p == bcm_static_skb->skb_4k[i]) { ++ bcm_static_skb->pkt_use[i] = 0; ++ up(&bcm_static_skb->osl_pkt_sem); ++ return; ++ } ++ } ++ ++ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { ++ if (p == bcm_static_skb->skb_8k[i]) { ++ bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 0; ++ up(&bcm_static_skb->osl_pkt_sem); ++ return; ++ } ++ } ++#ifdef ENHANCED_STATIC_BUF ++ if (p == bcm_static_skb->skb_16k) { ++ bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM*2] = 0; ++ up(&bcm_static_skb->osl_pkt_sem); ++ return; ++ } ++#endif ++ up(&bcm_static_skb->osl_pkt_sem); ++ ++ osl_pktfree(osh, p, send); ++ return; ++} ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++uint32 ++osl_pci_read_config(osl_t *osh, uint offset, uint size) ++{ ++ uint val = 0; ++ uint retry = PCI_CFG_RETRY; ++ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ ++ /* only 4byte access supported */ ++ ASSERT(size == 4); ++ ++ do { ++ pci_read_config_dword(osh->pdev, offset, &val); ++ if (val != 0xffffffff) ++ break; ++ } while (retry--); ++ ++ ++ return (val); ++} ++ ++void ++osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val) ++{ ++ uint retry = PCI_CFG_RETRY; ++ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ ++ /* only 4byte access supported */ ++ ASSERT(size == 4); ++ ++ do { ++ pci_write_config_dword(osh->pdev, offset, val); ++ if (offset != PCI_BAR0_WIN) ++ break; ++ if (osl_pci_read_config(osh, offset, size) == val) ++ break; ++ } while (retry--); ++ ++} ++ ++/* return bus # for the pci device pointed by osh->pdev */ ++uint ++osl_pci_bus(osl_t *osh) ++{ ++ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); ++ ++ return ((struct pci_dev *)osh->pdev)->bus->number; ++} ++ ++/* return slot # for the pci device pointed by osh->pdev */ ++uint ++osl_pci_slot(osl_t *osh) ++{ ++ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); ++ ++ return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn); ++} ++ ++/* return the pci device pointed by osh->pdev */ ++struct pci_dev * ++osl_pci_device(osl_t *osh) ++{ ++ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); ++ ++ return osh->pdev; ++} ++ ++static void ++osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write) ++{ ++} ++ ++void ++osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size) ++{ ++ osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE); ++} ++ ++void ++osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size) ++{ ++ osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE); ++} ++ ++void * ++osl_malloc(osl_t *osh, uint size) ++{ ++ void *addr; ++ ++ /* only ASSERT if osh is defined */ ++ if (osh) ++ ASSERT(osh->magic == OS_HANDLE_MAGIC); ++ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ if (bcm_static_buf) ++ { ++ int i = 0; ++ if ((size >= PAGE_SIZE)&&(size <= STATIC_BUF_SIZE)) ++ { ++ down(&bcm_static_buf->static_sem); ++ ++ for (i = 0; i < STATIC_BUF_MAX_NUM; i++) ++ { ++ if (bcm_static_buf->buf_use[i] == 0) ++ break; ++ } ++ ++ if (i == STATIC_BUF_MAX_NUM) ++ { ++ up(&bcm_static_buf->static_sem); ++ AP6211_DEBUG("all static buff in use!\n"); ++ goto original; ++ } ++ ++ bcm_static_buf->buf_use[i] = 1; ++ up(&bcm_static_buf->static_sem); ++ ++ bzero(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i, size); ++ if (osh) ++ atomic_add(size, &osh->malloced); ++ ++ return ((void *)(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i)); ++ } ++ } ++original: ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++ if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) { ++ if (osh) ++ osh->failed++; ++ return (NULL); ++ } ++ if (osh) ++ atomic_add(size, &osh->malloced); ++ ++ return (addr); ++} ++ ++void ++osl_mfree(osl_t *osh, void *addr, uint size) ++{ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ if (bcm_static_buf) ++ { ++ if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr ++ <= ((unsigned char *)bcm_static_buf + STATIC_BUF_TOTAL_LEN))) ++ { ++ int buf_idx = 0; ++ ++ buf_idx = ((unsigned char *)addr - bcm_static_buf->buf_ptr)/STATIC_BUF_SIZE; ++ ++ down(&bcm_static_buf->static_sem); ++ bcm_static_buf->buf_use[buf_idx] = 0; ++ up(&bcm_static_buf->static_sem); ++ ++ if (osh) { ++ ASSERT(osh->magic == OS_HANDLE_MAGIC); ++ atomic_sub(size, &osh->malloced); ++ } ++ return; ++ } ++ } ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ if (osh) { ++ ASSERT(osh->magic == OS_HANDLE_MAGIC); ++ atomic_sub(size, &osh->malloced); ++ } ++ kfree(addr); ++} ++ ++uint ++osl_malloced(osl_t *osh) ++{ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ return (atomic_read(&osh->malloced)); ++} ++ ++uint ++osl_malloc_failed(osl_t *osh) ++{ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ return (osh->failed); ++} ++ ++ ++uint ++osl_dma_consistent_align(void) ++{ ++ return (PAGE_SIZE); ++} ++ ++void* ++osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, uint *alloced, ulong *pap) ++{ ++ uint16 align = (1 << align_bits); ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ ++ if (!ISALIGNED(DMA_CONSISTENT_ALIGN, align)) ++ size += align; ++ *alloced = size; ++ ++ return (pci_alloc_consistent(osh->pdev, size, (dma_addr_t*)pap)); ++} ++ ++void ++osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa) ++{ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ ++ pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa); ++} ++ ++uint BCMFASTPATH ++osl_dma_map(osl_t *osh, void *va, uint size, int direction) ++{ ++ int dir; ++ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; ++ return (pci_map_single(osh->pdev, va, size, dir)); ++} ++ ++void BCMFASTPATH ++osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction) ++{ ++ int dir; ++ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; ++ pci_unmap_single(osh->pdev, (uint32)pa, size, dir); ++} ++ ++#if defined(BCMASSERT_LOG) ++void ++osl_assert(const char *exp, const char *file, int line) ++{ ++ char tempbuf[256]; ++ const char *basename; ++ ++ basename = strrchr(file, '/'); ++ /* skip the '/' */ ++ if (basename) ++ basename++; ++ ++ if (!basename) ++ basename = file; ++ ++ snprintf(tempbuf, 64, "\"%s\": file \"%s\", line %d\n", ++ exp, basename, line); ++ ++ AP6211_DEBUG("%s", tempbuf); ++ ++ ++} ++#endif ++ ++void ++osl_delay(uint usec) ++{ ++ uint d; ++ ++ while (usec > 0) { ++ d = MIN(usec, 1000); ++ udelay(d); ++ usec -= d; ++ } ++} ++ ++ ++/* Clone a packet. ++ * The pkttag contents are NOT cloned. ++ */ ++void * ++osl_pktdup(osl_t *osh, void *skb) ++{ ++ void * p; ++ unsigned long irqflags; ++ ++ /* clear the CTFBUF flag if set and map the rest of the buffer ++ * before cloning. ++ */ ++ PKTCTFMAP(osh, skb); ++ ++ if ((p = skb_clone((struct sk_buff *)skb, GFP_ATOMIC)) == NULL) ++ return NULL; ++ ++#ifdef CTFPOOL ++ if (PKTISFAST(osh, skb)) { ++ ctfpool_t *ctfpool; ++ ++ /* if the buffer allocated from ctfpool is cloned then ++ * we can't be sure when it will be freed. since there ++ * is a chance that we will be losing a buffer ++ * from our pool, we increment the refill count for the ++ * object to be alloced later. ++ */ ++ ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); ++ ASSERT(ctfpool != NULL); ++ PKTCLRFAST(osh, p); ++ PKTCLRFAST(osh, skb); ++ ctfpool->refills++; ++ } ++#endif /* CTFPOOL */ ++ ++ /* skb_clone copies skb->cb.. we don't want that */ ++ if (osh->pub.pkttag) ++ bzero((void*)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ); ++ ++ /* Increment the packet counter */ ++ spin_lock_irqsave(&osh->pktalloc_lock, irqflags); ++ osh->pub.pktalloced++; ++ spin_unlock_irqrestore(&osh->pktalloc_lock, irqflags); ++ return (p); ++} ++ ++ ++/* ++ * OSLREGOPS specifies the use of osl_XXX routines to be used for register access ++ */ ++ ++/* ++ * BINOSL selects the slightly slower function-call-based binary compatible osl. ++ */ ++ ++/* Linux Kernel: File Operations: start */ ++void * ++osl_os_open_image(char *filename) ++{ ++ struct file *fp; ++ ++ fp = filp_open(filename, O_RDONLY, 0); ++ /* ++ * 2.6.11 (FC4) supports filp_open() but later revs don't? ++ * Alternative: ++ * fp = open_namei(AT_FDCWD, filename, O_RD, 0); ++ * ??? ++ */ ++ if (IS_ERR(fp)) ++ fp = NULL; ++ ++ return fp; ++} ++ ++int ++osl_os_get_image_block(char *buf, int len, void *image) ++{ ++ struct file *fp = (struct file *)image; ++ int rdlen; ++ ++ if (!image) ++ return 0; ++ ++ rdlen = kernel_read(fp, fp->f_pos, buf, len); ++ if (rdlen > 0) ++ fp->f_pos += rdlen; ++ ++ return rdlen; ++} ++ ++void ++osl_os_close_image(void *image) ++{ ++ if (image) ++ filp_close((struct file *)image, NULL); ++} ++/* Linux Kernel: File Operations: end */ +diff --git a/drivers/net/wireless/ap6211/sbutils.c b/drivers/net/wireless/ap6211/sbutils.c +new file mode 100755 +index 0000000..89f9eb3 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/sbutils.c +@@ -0,0 +1,1003 @@ ++/* ++ * Misc utility routines for accessing chip-specific features ++ * of the SiliconBackplane-based Broadcom chips. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: sbutils.c 310902 2012-01-26 19:45:33Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "siutils_priv.h" ++ ++#include ++ ++ ++/* local prototypes */ ++static uint _sb_coreidx(si_info_t *sii, uint32 sba); ++static uint _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, ++ uint ncores); ++static uint32 _sb_coresba(si_info_t *sii); ++static void *_sb_setcoreidx(si_info_t *sii, uint coreidx); ++ ++#define SET_SBREG(sii, r, mask, val) \ ++ W_SBREG((sii), (r), ((R_SBREG((sii), (r)) & ~(mask)) | (val))) ++#define REGS2SB(va) (sbconfig_t*) ((int8*)(va) + SBCONFIGOFF) ++ ++/* sonicsrev */ ++#define SONICS_2_2 (SBIDL_RV_2_2 >> SBIDL_RV_SHIFT) ++#define SONICS_2_3 (SBIDL_RV_2_3 >> SBIDL_RV_SHIFT) ++ ++#define R_SBREG(sii, sbr) sb_read_sbreg((sii), (sbr)) ++#define W_SBREG(sii, sbr, v) sb_write_sbreg((sii), (sbr), (v)) ++#define AND_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) & (v))) ++#define OR_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) | (v))) ++ ++static uint32 ++sb_read_sbreg(si_info_t *sii, volatile uint32 *sbr) ++{ ++ uint8 tmp; ++ uint32 val, intr_val = 0; ++ ++ ++ /* ++ * compact flash only has 11 bits address, while we needs 12 bits address. ++ * MEM_SEG will be OR'd with other 11 bits address in hardware, ++ * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). ++ * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special ++ */ ++ if (PCMCIA(sii)) { ++ INTR_OFF(sii, intr_val); ++ tmp = 1; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); ++ sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ ++ } ++ ++ val = R_REG(sii->osh, sbr); ++ ++ if (PCMCIA(sii)) { ++ tmp = 0; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); ++ INTR_RESTORE(sii, intr_val); ++ } ++ ++ return (val); ++} ++ ++static void ++sb_write_sbreg(si_info_t *sii, volatile uint32 *sbr, uint32 v) ++{ ++ uint8 tmp; ++ volatile uint32 dummy; ++ uint32 intr_val = 0; ++ ++ ++ /* ++ * compact flash only has 11 bits address, while we needs 12 bits address. ++ * MEM_SEG will be OR'd with other 11 bits address in hardware, ++ * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). ++ * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special ++ */ ++ if (PCMCIA(sii)) { ++ INTR_OFF(sii, intr_val); ++ tmp = 1; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); ++ sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ ++ } ++ ++ if (BUSTYPE(sii->pub.bustype) == PCMCIA_BUS) { ++ dummy = R_REG(sii->osh, sbr); ++ BCM_REFERENCE(dummy); ++ W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); ++ dummy = R_REG(sii->osh, sbr); ++ BCM_REFERENCE(dummy); ++ W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); ++ } else ++ W_REG(sii->osh, sbr, v); ++ ++ if (PCMCIA(sii)) { ++ tmp = 0; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); ++ INTR_RESTORE(sii, intr_val); ++ } ++} ++ ++uint ++sb_coreid(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT); ++} ++ ++uint ++sb_intflag(si_t *sih) ++{ ++ si_info_t *sii; ++ void *corereg; ++ sbconfig_t *sb; ++ uint origidx, intflag, intr_val = 0; ++ ++ sii = SI_INFO(sih); ++ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ corereg = si_setcore(sih, CC_CORE_ID, 0); ++ ASSERT(corereg != NULL); ++ sb = REGS2SB(corereg); ++ intflag = R_SBREG(sii, &sb->sbflagst); ++ sb_setcoreidx(sih, origidx); ++ INTR_RESTORE(sii, intr_val); ++ ++ return intflag; ++} ++ ++uint ++sb_flag(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ return R_SBREG(sii, &sb->sbtpsflag) & SBTPS_NUM0_MASK; ++} ++ ++void ++sb_setint(si_t *sih, int siflag) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ uint32 vec; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ if (siflag == -1) ++ vec = 0; ++ else ++ vec = 1 << siflag; ++ W_SBREG(sii, &sb->sbintvec, vec); ++} ++ ++/* return core index of the core with address 'sba' */ ++static uint ++_sb_coreidx(si_info_t *sii, uint32 sba) ++{ ++ uint i; ++ ++ for (i = 0; i < sii->numcores; i ++) ++ if (sba == sii->coresba[i]) ++ return i; ++ return BADIDX; ++} ++ ++/* return core address of the current core */ ++static uint32 ++_sb_coresba(si_info_t *sii) ++{ ++ uint32 sbaddr; ++ ++ ++ switch (BUSTYPE(sii->pub.bustype)) { ++ case SI_BUS: { ++ sbconfig_t *sb = REGS2SB(sii->curmap); ++ sbaddr = sb_base(R_SBREG(sii, &sb->sbadmatch0)); ++ break; ++ } ++ ++ case PCI_BUS: ++ sbaddr = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); ++ break; ++ ++ case PCMCIA_BUS: { ++ uint8 tmp = 0; ++ OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1); ++ sbaddr = (uint32)tmp << 12; ++ OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1); ++ sbaddr |= (uint32)tmp << 16; ++ OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1); ++ sbaddr |= (uint32)tmp << 24; ++ break; ++ } ++ ++ case SPI_BUS: ++ case SDIO_BUS: ++ sbaddr = (uint32)(uintptr)sii->curmap; ++ break; ++ ++ ++ default: ++ sbaddr = BADCOREADDR; ++ break; ++ } ++ ++ return sbaddr; ++} ++ ++uint ++sb_corevendor(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT); ++} ++ ++uint ++sb_corerev(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ uint sbidh; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ sbidh = R_SBREG(sii, &sb->sbidhigh); ++ ++ return (SBCOREREV(sbidh)); ++} ++ ++/* set core-specific control flags */ ++void ++sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ uint32 w; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ ASSERT((val & ~mask) == 0); ++ ++ /* mask and set */ ++ w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) | ++ (val << SBTML_SICF_SHIFT); ++ W_SBREG(sii, &sb->sbtmstatelow, w); ++} ++ ++/* set/clear core-specific control flags */ ++uint32 ++sb_core_cflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ uint32 w; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ ASSERT((val & ~mask) == 0); ++ ++ /* mask and set */ ++ if (mask || val) { ++ w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) | ++ (val << SBTML_SICF_SHIFT); ++ W_SBREG(sii, &sb->sbtmstatelow, w); ++ } ++ ++ /* return the new value ++ * for write operation, the following readback ensures the completion of write opration. ++ */ ++ return (R_SBREG(sii, &sb->sbtmstatelow) >> SBTML_SICF_SHIFT); ++} ++ ++/* set/clear core-specific status flags */ ++uint32 ++sb_core_sflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ uint32 w; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ ASSERT((val & ~mask) == 0); ++ ASSERT((mask & ~SISF_CORE_BITS) == 0); ++ ++ /* mask and set */ ++ if (mask || val) { ++ w = (R_SBREG(sii, &sb->sbtmstatehigh) & ~(mask << SBTMH_SISF_SHIFT)) | ++ (val << SBTMH_SISF_SHIFT); ++ W_SBREG(sii, &sb->sbtmstatehigh, w); ++ } ++ ++ /* return the new value */ ++ return (R_SBREG(sii, &sb->sbtmstatehigh) >> SBTMH_SISF_SHIFT); ++} ++ ++bool ++sb_iscoreup(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ return ((R_SBREG(sii, &sb->sbtmstatelow) & ++ (SBTML_RESET | SBTML_REJ_MASK | (SICF_CLOCK_EN << SBTML_SICF_SHIFT))) == ++ (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); ++} ++ ++/* ++ * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation, ++ * switch back to the original core, and return the new value. ++ * ++ * When using the silicon backplane, no fidleing with interrupts or core switches are needed. ++ * ++ * Also, when using pci/pcie, we can optimize away the core switching for pci registers ++ * and (on newer pci cores) chipcommon registers. ++ */ ++uint ++sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) ++{ ++ uint origidx = 0; ++ uint32 *r = NULL; ++ uint w; ++ uint intr_val = 0; ++ bool fast = FALSE; ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ ASSERT(GOODIDX(coreidx)); ++ ASSERT(regoff < SI_CORE_SIZE); ++ ASSERT((val & ~mask) == 0); ++ ++ if (coreidx >= SI_MAXCORES) ++ return 0; ++ ++ if (BUSTYPE(sii->pub.bustype) == SI_BUS) { ++ /* If internal bus, we can always get at everything */ ++ fast = TRUE; ++ /* map if does not exist */ ++ if (!sii->regs[coreidx]) { ++ sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx], ++ SI_CORE_SIZE); ++ ASSERT(GOODREGS(sii->regs[coreidx])); ++ } ++ r = (uint32 *)((uchar *)sii->regs[coreidx] + regoff); ++ } else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { ++ /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ ++ ++ if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { ++ /* Chipc registers are mapped at 12KB */ ++ ++ fast = TRUE; ++ r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff); ++ } else if (sii->pub.buscoreidx == coreidx) { ++ /* pci registers are at either in the last 2KB of an 8KB window ++ * or, in pcie and pci rev 13 at 8KB ++ */ ++ fast = TRUE; ++ if (SI_FAST(sii)) ++ r = (uint32 *)((char *)sii->curmap + ++ PCI_16KB0_PCIREGS_OFFSET + regoff); ++ else ++ r = (uint32 *)((char *)sii->curmap + ++ ((regoff >= SBCONFIGOFF) ? ++ PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + ++ regoff); ++ } ++ } ++ ++ if (!fast) { ++ INTR_OFF(sii, intr_val); ++ ++ /* save current core index */ ++ origidx = si_coreidx(&sii->pub); ++ ++ /* switch core */ ++ r = (uint32*) ((uchar*)sb_setcoreidx(&sii->pub, coreidx) + regoff); ++ } ++ ASSERT(r != NULL); ++ ++ /* mask and set */ ++ if (mask || val) { ++ if (regoff >= SBCONFIGOFF) { ++ w = (R_SBREG(sii, r) & ~mask) | val; ++ W_SBREG(sii, r, w); ++ } else { ++ w = (R_REG(sii->osh, r) & ~mask) | val; ++ W_REG(sii->osh, r, w); ++ } ++ } ++ ++ /* readback */ ++ if (regoff >= SBCONFIGOFF) ++ w = R_SBREG(sii, r); ++ else { ++ if ((CHIPID(sii->pub.chip) == BCM5354_CHIP_ID) && ++ (coreidx == SI_CC_IDX) && ++ (regoff == OFFSETOF(chipcregs_t, watchdog))) { ++ w = val; ++ } else ++ w = R_REG(sii->osh, r); ++ } ++ ++ if (!fast) { ++ /* restore core index */ ++ if (origidx != coreidx) ++ sb_setcoreidx(&sii->pub, origidx); ++ ++ INTR_RESTORE(sii, intr_val); ++ } ++ ++ return (w); ++} ++ ++/* Scan the enumeration space to find all cores starting from the given ++ * bus 'sbba'. Append coreid and other info to the lists in 'si'. 'sba' ++ * is the default core address at chip POR time and 'regs' is the virtual ++ * address that the default core is mapped at. 'ncores' is the number of ++ * cores expected on bus 'sbba'. It returns the total number of cores ++ * starting from bus 'sbba', inclusive. ++ */ ++#define SB_MAXBUSES 2 ++static uint ++_sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint numcores) ++{ ++ uint next; ++ uint ncc = 0; ++ uint i; ++ ++ if (bus >= SB_MAXBUSES) { ++ AP6211_ERR("_sb_scan: bus 0x%08x at level %d is too deep to scan\n", sbba, bus); ++ return 0; ++ } ++ AP6211_DEBUG("_sb_scan: scan bus 0x%08x assume %u cores\n", sbba, numcores); ++ ++ /* Scan all cores on the bus starting from core 0. ++ * Core addresses must be contiguous on each bus. ++ */ ++ for (i = 0, next = sii->numcores; i < numcores && next < SB_BUS_MAXCORES; i++, next++) { ++ sii->coresba[next] = sbba + (i * SI_CORE_SIZE); ++ ++ /* keep and reuse the initial register mapping */ ++ if ((BUSTYPE(sii->pub.bustype) == SI_BUS) && (sii->coresba[next] == sba)) { ++ AP6211_DEBUG("_sb_scan: reuse mapped regs %p for core %u\n", regs, next); ++ sii->regs[next] = regs; ++ } ++ ++ /* change core to 'next' and read its coreid */ ++ sii->curmap = _sb_setcoreidx(sii, next); ++ sii->curidx = next; ++ ++ sii->coreid[next] = sb_coreid(&sii->pub); ++ ++ /* core specific processing... */ ++ /* chipc provides # cores */ ++ if (sii->coreid[next] == CC_CORE_ID) { ++ chipcregs_t *cc = (chipcregs_t *)sii->curmap; ++ uint32 ccrev = sb_corerev(&sii->pub); ++ ++ /* determine numcores - this is the total # cores in the chip */ ++ if (((ccrev == 4) || (ccrev >= 6))) ++ numcores = (R_REG(sii->osh, &cc->chipid) & CID_CC_MASK) >> ++ CID_CC_SHIFT; ++ else { ++ /* Older chips */ ++ uint chip = CHIPID(sii->pub.chip); ++ ++ if (chip == BCM4306_CHIP_ID) /* < 4306c0 */ ++ numcores = 6; ++ else if (chip == BCM4704_CHIP_ID) ++ numcores = 9; ++ else if (chip == BCM5365_CHIP_ID) ++ numcores = 7; ++ else { ++ AP6211_ERR("sb_chip2numcores: unsupported chip 0x%x\n", ++ chip); ++ ASSERT(0); ++ numcores = 1; ++ } ++ } ++ AP6211_DEBUG("_sb_scan: there are %u cores in the chip %s\n", numcores, ++ sii->pub.issim ? "QT" : ""); ++ } ++ /* scan bridged SB(s) and add results to the end of the list */ ++ else if (sii->coreid[next] == OCP_CORE_ID) { ++ sbconfig_t *sb = REGS2SB(sii->curmap); ++ uint32 nsbba = R_SBREG(sii, &sb->sbadmatch1); ++ uint nsbcc; ++ ++ sii->numcores = next + 1; ++ ++ if ((nsbba & 0xfff00000) != SI_ENUM_BASE) ++ continue; ++ nsbba &= 0xfffff000; ++ if (_sb_coreidx(sii, nsbba) != BADIDX) ++ continue; ++ ++ nsbcc = (R_SBREG(sii, &sb->sbtmstatehigh) & 0x000f0000) >> 16; ++ nsbcc = _sb_scan(sii, sba, regs, bus + 1, nsbba, nsbcc); ++ if (sbba == SI_ENUM_BASE) ++ numcores -= nsbcc; ++ ncc += nsbcc; ++ } ++ } ++ ++ AP6211_DEBUG("_sb_scan: found %u cores on bus 0x%08x\n", i, sbba); ++ ++ sii->numcores = i + ncc; ++ return sii->numcores; ++} ++ ++/* scan the sb enumerated space to identify all cores */ ++void ++sb_scan(si_t *sih, void *regs, uint devid) ++{ ++ si_info_t *sii; ++ uint32 origsba; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ sii->pub.socirev = (R_SBREG(sii, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT; ++ ++ /* Save the current core info and validate it later till we know ++ * for sure what is good and what is bad. ++ */ ++ origsba = _sb_coresba(sii); ++ ++ /* scan all SB(s) starting from SI_ENUM_BASE */ ++ sii->numcores = _sb_scan(sii, origsba, regs, 0, SI_ENUM_BASE, 1); ++} ++ ++/* ++ * This function changes logical "focus" to the indicated core; ++ * must be called with interrupts off. ++ * Moreover, callers should keep interrupts off during switching out of and back to d11 core ++ */ ++void * ++sb_setcoreidx(si_t *sih, uint coreidx) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ if (coreidx >= sii->numcores) ++ return (NULL); ++ ++ /* ++ * If the user has provided an interrupt mask enabled function, ++ * then assert interrupts are disabled before switching the core. ++ */ ++ ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); ++ ++ sii->curmap = _sb_setcoreidx(sii, coreidx); ++ sii->curidx = coreidx; ++ ++ return (sii->curmap); ++} ++ ++/* This function changes the logical "focus" to the indicated core. ++ * Return the current core's virtual address. ++ */ ++static void * ++_sb_setcoreidx(si_info_t *sii, uint coreidx) ++{ ++ uint32 sbaddr = sii->coresba[coreidx]; ++ void *regs; ++ ++ switch (BUSTYPE(sii->pub.bustype)) { ++ case SI_BUS: ++ /* map new one */ ++ if (!sii->regs[coreidx]) { ++ sii->regs[coreidx] = REG_MAP(sbaddr, SI_CORE_SIZE); ++ ASSERT(GOODREGS(sii->regs[coreidx])); ++ } ++ regs = sii->regs[coreidx]; ++ break; ++ ++ case PCI_BUS: ++ /* point bar0 window */ ++ OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, sbaddr); ++ regs = sii->curmap; ++ break; ++ ++ case PCMCIA_BUS: { ++ uint8 tmp = (sbaddr >> 12) & 0x0f; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1); ++ tmp = (sbaddr >> 16) & 0xff; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1); ++ tmp = (sbaddr >> 24) & 0xff; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1); ++ regs = sii->curmap; ++ break; ++ } ++ case SPI_BUS: ++ case SDIO_BUS: ++ /* map new one */ ++ if (!sii->regs[coreidx]) { ++ sii->regs[coreidx] = (void *)(uintptr)sbaddr; ++ ASSERT(GOODREGS(sii->regs[coreidx])); ++ } ++ regs = sii->regs[coreidx]; ++ break; ++ ++ ++ default: ++ ASSERT(0); ++ regs = NULL; ++ break; ++ } ++ ++ return regs; ++} ++ ++/* Return the address of sbadmatch0/1/2/3 register */ ++static volatile uint32 * ++sb_admatch(si_info_t *sii, uint asidx) ++{ ++ sbconfig_t *sb; ++ volatile uint32 *addrm; ++ ++ sb = REGS2SB(sii->curmap); ++ ++ switch (asidx) { ++ case 0: ++ addrm = &sb->sbadmatch0; ++ break; ++ ++ case 1: ++ addrm = &sb->sbadmatch1; ++ break; ++ ++ case 2: ++ addrm = &sb->sbadmatch2; ++ break; ++ ++ case 3: ++ addrm = &sb->sbadmatch3; ++ break; ++ ++ default: ++ AP6211_ERR("%s: Address space index (%d) out of range\n", __FUNCTION__, asidx); ++ return 0; ++ } ++ ++ return (addrm); ++} ++ ++/* Return the number of address spaces in current core */ ++int ++sb_numaddrspaces(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ /* + 1 because of enumeration space */ ++ return ((R_SBREG(sii, &sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT) + 1; ++} ++ ++/* Return the address of the nth address space in the current core */ ++uint32 ++sb_addrspace(si_t *sih, uint asidx) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ return (sb_base(R_SBREG(sii, sb_admatch(sii, asidx)))); ++} ++ ++/* Return the size of the nth address space in the current core */ ++uint32 ++sb_addrspacesize(si_t *sih, uint asidx) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ return (sb_size(R_SBREG(sii, sb_admatch(sii, asidx)))); ++} ++ ++ ++/* do buffered registers update */ ++void ++sb_commit(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ ++ sii = SI_INFO(sih); ++ ++ origidx = sii->curidx; ++ ASSERT(GOODIDX(origidx)); ++ ++ INTR_OFF(sii, intr_val); ++ ++ /* switch over to chipcommon core if there is one, else use pci */ ++ if (sii->pub.ccrev != NOREV) { ++ chipcregs_t *ccregs = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ASSERT(ccregs != NULL); ++ ++ /* do the buffer registers update */ ++ W_REG(sii->osh, &ccregs->broadcastaddress, SB_COMMIT); ++ W_REG(sii->osh, &ccregs->broadcastdata, 0x0); ++ } else ++ ASSERT(0); ++ ++ /* restore core index */ ++ sb_setcoreidx(sih, origidx); ++ INTR_RESTORE(sii, intr_val); ++} ++ ++void ++sb_core_disable(si_t *sih, uint32 bits) ++{ ++ si_info_t *sii; ++ volatile uint32 dummy; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ ++ ASSERT(GOODREGS(sii->curmap)); ++ sb = REGS2SB(sii->curmap); ++ ++ /* if core is already in reset, just return */ ++ if (R_SBREG(sii, &sb->sbtmstatelow) & SBTML_RESET) ++ return; ++ ++ /* if clocks are not enabled, put into reset and return */ ++ if ((R_SBREG(sii, &sb->sbtmstatelow) & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) == 0) ++ goto disable; ++ ++ /* set target reject and spin until busy is clear (preserve core-specific bits) */ ++ OR_SBREG(sii, &sb->sbtmstatelow, SBTML_REJ); ++ dummy = R_SBREG(sii, &sb->sbtmstatelow); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++ SPINWAIT((R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY), 100000); ++ if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY) ++ AP6211_ERR("%s: target state still busy\n", __FUNCTION__); ++ ++ if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) { ++ OR_SBREG(sii, &sb->sbimstate, SBIM_RJ); ++ dummy = R_SBREG(sii, &sb->sbimstate); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++ SPINWAIT((R_SBREG(sii, &sb->sbimstate) & SBIM_BY), 100000); ++ } ++ ++ /* set reset and reject while enabling the clocks */ ++ W_SBREG(sii, &sb->sbtmstatelow, ++ (((bits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | ++ SBTML_REJ | SBTML_RESET)); ++ dummy = R_SBREG(sii, &sb->sbtmstatelow); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(10); ++ ++ /* don't forget to clear the initiator reject bit */ ++ if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) ++ AND_SBREG(sii, &sb->sbimstate, ~SBIM_RJ); ++ ++disable: ++ /* leave reset and reject asserted */ ++ W_SBREG(sii, &sb->sbtmstatelow, ((bits << SBTML_SICF_SHIFT) | SBTML_REJ | SBTML_RESET)); ++ OSL_DELAY(1); ++} ++ ++/* reset and re-enable a core ++ * inputs: ++ * bits - core specific bits that are set during and after reset sequence ++ * resetbits - core specific bits that are set only during reset sequence ++ */ ++void ++sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ volatile uint32 dummy; ++ ++ sii = SI_INFO(sih); ++ ASSERT(GOODREGS(sii->curmap)); ++ sb = REGS2SB(sii->curmap); ++ ++ /* ++ * Must do the disable sequence first to work for arbitrary current core state. ++ */ ++ sb_core_disable(sih, (bits | resetbits)); ++ ++ /* ++ * Now do the initialization sequence. ++ */ ++ ++ /* set reset while enabling the clock and forcing them on throughout the core */ ++ W_SBREG(sii, &sb->sbtmstatelow, ++ (((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | ++ SBTML_RESET)); ++ dummy = R_SBREG(sii, &sb->sbtmstatelow); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++ ++ if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_SERR) { ++ W_SBREG(sii, &sb->sbtmstatehigh, 0); ++ } ++ if ((dummy = R_SBREG(sii, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO)) { ++ AND_SBREG(sii, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO)); ++ } ++ ++ /* clear reset and allow it to propagate throughout the core */ ++ W_SBREG(sii, &sb->sbtmstatelow, ++ ((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); ++ dummy = R_SBREG(sii, &sb->sbtmstatelow); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++ ++ /* leave clock enabled */ ++ W_SBREG(sii, &sb->sbtmstatelow, ((bits | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); ++ dummy = R_SBREG(sii, &sb->sbtmstatelow); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++} ++ ++/* ++ * Set the initiator timeout for the "master core". ++ * The master core is defined to be the core in control ++ * of the chip and so it issues accesses to non-memory ++ * locations (Because of dma *any* core can access memeory). ++ * ++ * The routine uses the bus to decide who is the master: ++ * SI_BUS => mips ++ * JTAG_BUS => chipc ++ * PCI_BUS => pci or pcie ++ * PCMCIA_BUS => pcmcia ++ * SDIO_BUS => pcmcia ++ * ++ * This routine exists so callers can disable initiator ++ * timeouts so accesses to very slow devices like otp ++ * won't cause an abort. The routine allows arbitrary ++ * settings of the service and request timeouts, though. ++ * ++ * Returns the timeout state before changing it or -1 ++ * on error. ++ */ ++ ++#define TO_MASK (SBIMCL_RTO_MASK | SBIMCL_STO_MASK) ++ ++uint32 ++sb_set_initiator_to(si_t *sih, uint32 to, uint idx) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ uint32 tmp, ret = 0xffffffff; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ ++ if ((to & ~TO_MASK) != 0) ++ return ret; ++ ++ /* Figure out the master core */ ++ if (idx == BADIDX) { ++ switch (BUSTYPE(sii->pub.bustype)) { ++ case PCI_BUS: ++ idx = sii->pub.buscoreidx; ++ break; ++ case JTAG_BUS: ++ idx = SI_CC_IDX; ++ break; ++ case PCMCIA_BUS: ++ case SDIO_BUS: ++ idx = si_findcoreidx(sih, PCMCIA_CORE_ID, 0); ++ break; ++ case SI_BUS: ++ idx = si_findcoreidx(sih, MIPS33_CORE_ID, 0); ++ break; ++ default: ++ ASSERT(0); ++ } ++ if (idx == BADIDX) ++ return ret; ++ } ++ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ sb = REGS2SB(sb_setcoreidx(sih, idx)); ++ ++ tmp = R_SBREG(sii, &sb->sbimconfiglow); ++ ret = tmp & TO_MASK; ++ W_SBREG(sii, &sb->sbimconfiglow, (tmp & ~TO_MASK) | to); ++ ++ sb_commit(sih); ++ sb_setcoreidx(sih, origidx); ++ INTR_RESTORE(sii, intr_val); ++ return ret; ++} ++ ++uint32 ++sb_base(uint32 admatch) ++{ ++ uint32 base; ++ uint type; ++ ++ type = admatch & SBAM_TYPE_MASK; ++ ASSERT(type < 3); ++ ++ base = 0; ++ ++ if (type == 0) { ++ base = admatch & SBAM_BASE0_MASK; ++ } else if (type == 1) { ++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ ++ base = admatch & SBAM_BASE1_MASK; ++ } else if (type == 2) { ++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ ++ base = admatch & SBAM_BASE2_MASK; ++ } ++ ++ return (base); ++} ++ ++uint32 ++sb_size(uint32 admatch) ++{ ++ uint32 size; ++ uint type; ++ ++ type = admatch & SBAM_TYPE_MASK; ++ ASSERT(type < 3); ++ ++ size = 0; ++ ++ if (type == 0) { ++ size = 1 << (((admatch & SBAM_ADINT0_MASK) >> SBAM_ADINT0_SHIFT) + 1); ++ } else if (type == 1) { ++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ ++ size = 1 << (((admatch & SBAM_ADINT1_MASK) >> SBAM_ADINT1_SHIFT) + 1); ++ } else if (type == 2) { ++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ ++ size = 1 << (((admatch & SBAM_ADINT2_MASK) >> SBAM_ADINT2_SHIFT) + 1); ++ } ++ ++ return (size); ++} +diff --git a/drivers/net/wireless/ap6211/siutils.c b/drivers/net/wireless/ap6211/siutils.c +new file mode 100755 +index 0000000..f917c41 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/siutils.c +@@ -0,0 +1,2472 @@ ++/* ++ * Misc utility routines for accessing chip-specific features ++ * of the SiliconBackplane-based Broadcom chips. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: siutils.c 347632 2012-07-27 11:00:35Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "siutils_priv.h" ++ ++#include ++ ++/* local prototypes */ ++static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, ++ uint bustype, void *sdh, char **vars, uint *varsz); ++static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh); ++static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, ++ uint *origidx, void *regs); ++ ++ ++ ++/* global variable to indicate reservation/release of gpio's */ ++static uint32 si_gpioreservation = 0; ++ ++/* global flag to prevent shared resources from being initialized multiple times in si_attach() */ ++ ++int do_4360_pcie2_war = 0; ++ ++/* ++ * Allocate a si handle. ++ * devid - pci device id (used to determine chip#) ++ * osh - opaque OS handle ++ * regs - virtual address of initial core registers ++ * bustype - pci/pcmcia/sb/sdio/etc ++ * vars - pointer to a pointer area for "environment" variables ++ * varsz - pointer to int to return the size of the vars ++ */ ++si_t * ++si_attach(uint devid, osl_t *osh, void *regs, ++ uint bustype, void *sdh, char **vars, uint *varsz) ++{ ++ si_info_t *sii; ++ ++ /* alloc si_info_t */ ++ if ((sii = MALLOC(osh, sizeof (si_info_t))) == NULL) { ++ AP6211_ERR("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh)); ++ return (NULL); ++ } ++ ++ if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) { ++ MFREE(osh, sii, sizeof(si_info_t)); ++ return (NULL); ++ } ++ sii->vars = vars ? *vars : NULL; ++ sii->varsz = varsz ? *varsz : 0; ++ ++ return (si_t *)sii; ++} ++ ++/* global kernel resource */ ++static si_info_t ksii; ++ ++static uint32 wd_msticks; /* watchdog timer ticks normalized to ms */ ++ ++/* generic kernel variant of si_attach() */ ++si_t * ++si_kattach(osl_t *osh) ++{ ++ static bool ksii_attached = FALSE; ++ ++ if (!ksii_attached) { ++ void *regs = NULL; ++ regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); ++ ++ if (si_doattach(&ksii, BCM4710_DEVICE_ID, osh, regs, ++ SI_BUS, NULL, ++ osh != SI_OSH ? &ksii.vars : NULL, ++ osh != SI_OSH ? &ksii.varsz : NULL) == NULL) { ++ AP6211_ERR("si_kattach: si_doattach failed\n"); ++ REG_UNMAP(regs); ++ return NULL; ++ } ++ REG_UNMAP(regs); ++ ++ /* save ticks normalized to ms for si_watchdog_ms() */ ++ if (PMUCTL_ENAB(&ksii.pub)) { ++ /* based on 32KHz ILP clock */ ++ wd_msticks = 32; ++ } else { ++ wd_msticks = ALP_CLOCK / 1000; ++ } ++ ++ ksii_attached = TRUE; ++ AP6211_DEBUG("si_kattach done. ccrev = %d, wd_msticks = %d\n", ++ ksii.pub.ccrev, wd_msticks); ++ } ++ ++ return &ksii.pub; ++} ++ ++ ++static bool ++si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh) ++{ ++ /* need to set memseg flag for CF card first before any sb registers access */ ++ if (BUSTYPE(bustype) == PCMCIA_BUS) ++ sii->memseg = TRUE; ++ ++ ++ if (BUSTYPE(bustype) == SDIO_BUS) { ++ int err; ++ uint8 clkset; ++ ++ /* Try forcing SDIO core to do ALPAvail request only */ ++ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); ++ if (!err) { ++ uint8 clkval; ++ ++ /* If register supported, wait for ALPAvail and then force ALP */ ++ clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL); ++ if ((clkval & ~SBSDIO_AVBITS) == clkset) { ++ SPINWAIT(((clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)), ++ PMU_MAX_TRANSITION_DLY); ++ if (!SBSDIO_ALPAV(clkval)) { ++ AP6211_ERR("timeout on ALPAV wait, clkval 0x%02x\n", ++ clkval); ++ return FALSE; ++ } ++ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ clkset, &err); ++ OSL_DELAY(65); ++ } ++ } ++ ++ /* Also, disable the extra SDIO pull-ups */ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); ++ } ++ ++ ++ return TRUE; ++} ++ ++static bool ++si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, ++ uint *origidx, void *regs) ++{ ++ bool pci, pcie, pcie_gen2 = FALSE; ++ uint i; ++ uint pciidx, pcieidx, pcirev, pcierev; ++ ++ cc = si_setcoreidx(&sii->pub, SI_CC_IDX); ++ ASSERT((uintptr)cc); ++ ++ /* get chipcommon rev */ ++ sii->pub.ccrev = (int)si_corerev(&sii->pub); ++ ++ /* get chipcommon chipstatus */ ++ if (sii->pub.ccrev >= 11) ++ sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus); ++ ++ /* get chipcommon capabilites */ ++ sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities); ++ /* get chipcommon extended capabilities */ ++ ++ if (sii->pub.ccrev >= 35) ++ sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext); ++ ++ /* get pmu rev and caps */ ++ if (sii->pub.cccaps & CC_CAP_PMU) { ++ sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities); ++ sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; ++ } ++ ++ AP6211_DEBUG("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n", ++ sii->pub.ccrev, sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev, ++ sii->pub.pmucaps); ++ ++ /* figure out bus/orignal core idx */ ++ sii->pub.buscoretype = NODEV_CORE_ID; ++ sii->pub.buscorerev = (uint)NOREV; ++ sii->pub.buscoreidx = BADIDX; ++ ++ pci = pcie = FALSE; ++ pcirev = pcierev = (uint)NOREV; ++ pciidx = pcieidx = BADIDX; ++ ++ for (i = 0; i < sii->numcores; i++) { ++ uint cid, crev; ++ ++ si_setcoreidx(&sii->pub, i); ++ cid = si_coreid(&sii->pub); ++ crev = si_corerev(&sii->pub); ++ ++ /* Display cores found */ ++ AP6211_DEBUG("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n", ++ i, cid, crev, sii->coresba[i], sii->regs[i]); ++ ++ if (BUSTYPE(bustype) == PCI_BUS) { ++ if (cid == PCI_CORE_ID) { ++ pciidx = i; ++ pcirev = crev; ++ pci = TRUE; ++ } else if ((cid == PCIE_CORE_ID) || (cid == PCIE2_CORE_ID)) { ++ pcieidx = i; ++ pcierev = crev; ++ pcie = TRUE; ++ if (cid == PCIE2_CORE_ID) ++ pcie_gen2 = TRUE; ++ } ++ } else if ((BUSTYPE(bustype) == PCMCIA_BUS) && ++ (cid == PCMCIA_CORE_ID)) { ++ sii->pub.buscorerev = crev; ++ sii->pub.buscoretype = cid; ++ sii->pub.buscoreidx = i; ++ } ++ else if (((BUSTYPE(bustype) == SDIO_BUS) || ++ (BUSTYPE(bustype) == SPI_BUS)) && ++ ((cid == PCMCIA_CORE_ID) || ++ (cid == SDIOD_CORE_ID))) { ++ sii->pub.buscorerev = crev; ++ sii->pub.buscoretype = cid; ++ sii->pub.buscoreidx = i; ++ } ++ ++ /* find the core idx before entering this func. */ ++ if ((savewin && (savewin == sii->coresba[i])) || ++ (regs == sii->regs[i])) ++ *origidx = i; ++ } ++ ++ if (pci) { ++ sii->pub.buscoretype = PCI_CORE_ID; ++ sii->pub.buscorerev = pcirev; ++ sii->pub.buscoreidx = pciidx; ++ } else if (pcie) { ++ if (pcie_gen2) ++ sii->pub.buscoretype = PCIE2_CORE_ID; ++ else ++ sii->pub.buscoretype = PCIE_CORE_ID; ++ sii->pub.buscorerev = pcierev; ++ sii->pub.buscoreidx = pcieidx; ++ } ++ ++ AP6211_DEBUG("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype, ++ sii->pub.buscorerev); ++ ++ if (BUSTYPE(sii->pub.bustype) == SI_BUS && (CHIPID(sii->pub.chip) == BCM4712_CHIP_ID) && ++ (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (CHIPREV(sii->pub.chiprev) <= 3)) ++ OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL); ++ ++ ++ /* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was ++ * already running. ++ */ ++ if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) { ++ if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) || ++ si_setcore(&sii->pub, ARMCM3_CORE_ID, 0)) ++ si_core_disable(&sii->pub, 0); ++ } ++ ++ /* return to the original core */ ++ si_setcoreidx(&sii->pub, *origidx); ++ ++ return TRUE; ++} ++ ++ ++ ++ ++static si_info_t * ++si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, ++ uint bustype, void *sdh, char **vars, uint *varsz) ++{ ++ struct si_pub *sih = &sii->pub; ++ uint32 w, savewin; ++ chipcregs_t *cc; ++ char *pvars = NULL; ++ uint origidx; ++ ++ ASSERT(GOODREGS(regs)); ++ ++ bzero((uchar*)sii, sizeof(si_info_t)); ++ ++ savewin = 0; ++ ++ sih->buscoreidx = BADIDX; ++ ++ sii->curmap = regs; ++ sii->sdh = sdh; ++ sii->osh = osh; ++ ++ ++ ++ /* find Chipcommon address */ ++ if (bustype == PCI_BUS) { ++ savewin = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); ++ if (!GOODCOREADDR(savewin, SI_ENUM_BASE)) ++ savewin = SI_ENUM_BASE; ++ OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE); ++ if (!regs) ++ return NULL; ++ cc = (chipcregs_t *)regs; ++ } else if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) { ++ cc = (chipcregs_t *)sii->curmap; ++ } else { ++ cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); ++ } ++ ++ sih->bustype = bustype; ++ if (bustype != BUSTYPE(bustype)) { ++ AP6211_ERR("si_doattach: bus type %d does not match configured bus type %d\n", ++ bustype, BUSTYPE(bustype)); ++ return NULL; ++ } ++ ++ /* bus/core/clk setup for register access */ ++ if (!si_buscore_prep(sii, bustype, devid, sdh)) { ++ AP6211_ERR("si_doattach: si_core_clk_prep failed %d\n", bustype); ++ return NULL; ++ } ++ ++ /* ChipID recognition. ++ * We assume we can read chipid at offset 0 from the regs arg. ++ * If we add other chiptypes (or if we need to support old sdio hosts w/o chipcommon), ++ * some way of recognizing them needs to be added here. ++ */ ++ if (!cc) { ++ AP6211_ERR("%s: chipcommon register space is null \n", __FUNCTION__); ++ return NULL; ++ } ++ w = R_REG(osh, &cc->chipid); ++ sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT; ++ /* Might as wll fill in chip id rev & pkg */ ++ sih->chip = w & CID_ID_MASK; ++ sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; ++ sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT; ++ ++#if defined(HW_OOB) ++ bcmsdh_config_hw_oob_intr(sdh, sih->chip); ++#endif ++ ++ if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 0) && ++ (sih->chippkg != BCM4329_289PIN_PKG_ID)) { ++ sih->chippkg = BCM4329_182PIN_PKG_ID; ++ } ++ sih->issim = IS_SIM(sih->chippkg); ++ ++ /* scan for cores */ ++ if (CHIPTYPE(sii->pub.socitype) == SOCI_SB) { ++ AP6211_DEBUG("Found chip type SB (0x%08x)\n", w); ++ sb_scan(&sii->pub, regs, devid); ++ } else if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) { ++ AP6211_DEBUG("Found chip type AI (0x%08x)\n", w); ++ /* pass chipc address instead of original core base */ ++ ai_scan(&sii->pub, (void *)(uintptr)cc, devid); ++ } else if (CHIPTYPE(sii->pub.socitype) == SOCI_UBUS) { ++ AP6211_DEBUG("Found chip type UBUS (0x%08x), chip id = 0x%4x\n", w, sih->chip); ++ /* pass chipc address instead of original core base */ ++ ub_scan(&sii->pub, (void *)(uintptr)cc, devid); ++ } else { ++ AP6211_ERR("Found chip of unknown type (0x%08x)\n", w); ++ return NULL; ++ } ++ /* no cores found, bail out */ ++ if (sii->numcores == 0) { ++ AP6211_ERR("si_doattach: could not find any cores\n"); ++ return NULL; ++ } ++ /* bus/core/clk setup */ ++ origidx = SI_CC_IDX; ++ if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) { ++ AP6211_ERR("si_doattach: si_buscore_setup failed\n"); ++ goto exit; ++ } ++ ++ if (CHIPID(sih->chip) == BCM4322_CHIP_ID && (((sih->chipst & CST4322_SPROM_OTP_SEL_MASK) ++ >> CST4322_SPROM_OTP_SEL_SHIFT) == (CST4322_OTP_PRESENT | ++ CST4322_SPROM_PRESENT))) { ++ AP6211_ERR("%s: Invalid setting: both SPROM and OTP strapped.\n", __FUNCTION__); ++ return NULL; ++ } ++ ++ /* assume current core is CC */ ++ if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43236_CHIP_ID || ++ CHIPID(sih->chip) == BCM43235_CHIP_ID || ++ CHIPID(sih->chip) == BCM43234_CHIP_ID || ++ CHIPID(sih->chip) == BCM43238_CHIP_ID) && ++ (CHIPREV(sii->pub.chiprev) <= 2))) { ++ ++ if ((cc->chipstatus & CST43236_BP_CLK) != 0) { ++ uint clkdiv; ++ clkdiv = R_REG(osh, &cc->clkdiv); ++ /* otp_clk_div is even number, 120/14 < 9mhz */ ++ clkdiv = (clkdiv & ~CLKD_OTP) | (14 << CLKD_OTP_SHIFT); ++ W_REG(osh, &cc->clkdiv, clkdiv); ++ AP6211_ERR("%s: set clkdiv to %x\n", __FUNCTION__, clkdiv); ++ } ++ OSL_DELAY(10); ++ } ++ ++ if (bustype == PCI_BUS) { ++ ++ } ++ ++ pvars = NULL; ++ BCM_REFERENCE(pvars); ++ ++ ++ ++ if (sii->pub.ccrev >= 20) { ++ uint32 gpiopullup = 0, gpiopulldown = 0; ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ASSERT(cc != NULL); ++ ++ /* 4314/43142 has pin muxing, don't clear gpio bits */ ++ if ((CHIPID(sih->chip) == BCM4314_CHIP_ID) || ++ (CHIPID(sih->chip) == BCM43142_CHIP_ID)) { ++ gpiopullup |= 0x402e0; ++ gpiopulldown |= 0x20500; ++ } ++ ++ W_REG(osh, &cc->gpiopullup, gpiopullup); ++ W_REG(osh, &cc->gpiopulldown, gpiopulldown); ++ si_setcoreidx(sih, origidx); ++ } ++ ++ ++ /* clear any previous epidiag-induced target abort */ ++ ASSERT(!si_taclear(sih, FALSE)); ++ ++ return (sii); ++ ++exit: ++ ++ return NULL; ++} ++ ++/* may be called with core in reset */ ++void ++si_detach(si_t *sih) ++{ ++ si_info_t *sii; ++ uint idx; ++ ++ ++ sii = SI_INFO(sih); ++ ++ if (sii == NULL) ++ return; ++ ++ if (BUSTYPE(sih->bustype) == SI_BUS) ++ for (idx = 0; idx < SI_MAXCORES; idx++) ++ if (sii->regs[idx]) { ++ REG_UNMAP(sii->regs[idx]); ++ sii->regs[idx] = NULL; ++ } ++ ++ ++ ++#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) ++ if (sii != &ksii) ++#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ ++ MFREE(sii->osh, sii, sizeof(si_info_t)); ++} ++ ++void * ++si_osh(si_t *sih) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ return sii->osh; ++} ++ ++void ++si_setosh(si_t *sih, osl_t *osh) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ if (sii->osh != NULL) { ++ AP6211_ERR("osh is already set....\n"); ++ ASSERT(!sii->osh); ++ } ++ sii->osh = osh; ++} ++ ++/* register driver interrupt disabling and restoring callback functions */ ++void ++si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, ++ void *intrsenabled_fn, void *intr_arg) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ sii->intr_arg = intr_arg; ++ sii->intrsoff_fn = (si_intrsoff_t)intrsoff_fn; ++ sii->intrsrestore_fn = (si_intrsrestore_t)intrsrestore_fn; ++ sii->intrsenabled_fn = (si_intrsenabled_t)intrsenabled_fn; ++ /* save current core id. when this function called, the current core ++ * must be the core which provides driver functions(il, et, wl, etc.) ++ */ ++ sii->dev_coreid = sii->coreid[sii->curidx]; ++} ++ ++void ++si_deregister_intr_callback(si_t *sih) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ sii->intrsoff_fn = NULL; ++} ++ ++uint ++si_intflag(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_intflag(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return R_REG(sii->osh, ((uint32 *)(uintptr) ++ (sii->oob_router + OOB_STATUSA))); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++uint ++si_flag(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_flag(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_flag(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_flag(sih); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++void ++si_setint(si_t *sih, int siflag) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ sb_setint(sih, siflag); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ ai_setint(sih, siflag); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ ub_setint(sih, siflag); ++ else ++ ASSERT(0); ++} ++ ++uint ++si_coreid(si_t *sih) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ return sii->coreid[sii->curidx]; ++} ++ ++uint ++si_coreidx(si_t *sih) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ return sii->curidx; ++} ++ ++/* return the core-type instantiation # of the current core */ ++uint ++si_coreunit(si_t *sih) ++{ ++ si_info_t *sii; ++ uint idx; ++ uint coreid; ++ uint coreunit; ++ uint i; ++ ++ sii = SI_INFO(sih); ++ coreunit = 0; ++ ++ idx = sii->curidx; ++ ++ ASSERT(GOODREGS(sii->curmap)); ++ coreid = si_coreid(sih); ++ ++ /* count the cores of our type */ ++ for (i = 0; i < idx; i++) ++ if (sii->coreid[i] == coreid) ++ coreunit++; ++ ++ return (coreunit); ++} ++ ++uint ++si_corevendor(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_corevendor(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_corevendor(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_corevendor(sih); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++bool ++si_backplane64(si_t *sih) ++{ ++ return ((sih->cccaps & CC_CAP_BKPLN64) != 0); ++} ++ ++uint ++si_corerev(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_corerev(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_corerev(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_corerev(sih); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++/* return index of coreid or BADIDX if not found */ ++uint ++si_findcoreidx(si_t *sih, uint coreid, uint coreunit) ++{ ++ si_info_t *sii; ++ uint found; ++ uint i; ++ ++ sii = SI_INFO(sih); ++ ++ found = 0; ++ ++ for (i = 0; i < sii->numcores; i++) ++ if (sii->coreid[i] == coreid) { ++ if (found == coreunit) ++ return (i); ++ found++; ++ } ++ ++ return (BADIDX); ++} ++ ++/* return list of found cores */ ++uint ++si_corelist(si_t *sih, uint coreid[]) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ bcopy((uchar*)sii->coreid, (uchar*)coreid, (sii->numcores * sizeof(uint))); ++ return (sii->numcores); ++} ++ ++/* return current register mapping */ ++void * ++si_coreregs(si_t *sih) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ASSERT(GOODREGS(sii->curmap)); ++ ++ return (sii->curmap); ++} ++ ++/* ++ * This function changes logical "focus" to the indicated core; ++ * must be called with interrupts off. ++ * Moreover, callers should keep interrupts off during switching out of and back to d11 core ++ */ ++void * ++si_setcore(si_t *sih, uint coreid, uint coreunit) ++{ ++ uint idx; ++ ++ idx = si_findcoreidx(sih, coreid, coreunit); ++ if (!GOODIDX(idx)) ++ return (NULL); ++ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_setcoreidx(sih, idx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_setcoreidx(sih, idx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_setcoreidx(sih, idx); ++ else { ++ ASSERT(0); ++ return NULL; ++ } ++} ++ ++void * ++si_setcoreidx(si_t *sih, uint coreidx) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_setcoreidx(sih, coreidx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_setcoreidx(sih, coreidx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_setcoreidx(sih, coreidx); ++ else { ++ ASSERT(0); ++ return NULL; ++ } ++} ++ ++/* Turn off interrupt as required by sb_setcore, before switch core */ ++void * ++si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val) ++{ ++ void *cc; ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ if (SI_FAST(sii)) { ++ /* Overloading the origidx variable to remember the coreid, ++ * this works because the core ids cannot be confused with ++ * core indices. ++ */ ++ *origidx = coreid; ++ if (coreid == CC_CORE_ID) ++ return (void *)CCREGS_FAST(sii); ++ else if (coreid == sih->buscoretype) ++ return (void *)PCIEREGS(sii); ++ } ++ INTR_OFF(sii, *intr_val); ++ *origidx = sii->curidx; ++ cc = si_setcore(sih, coreid, 0); ++ ASSERT(cc != NULL); ++ ++ return cc; ++} ++ ++/* restore coreidx and restore interrupt */ ++void ++si_restore_core(si_t *sih, uint coreid, uint intr_val) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ if (SI_FAST(sii) && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype))) ++ return; ++ ++ si_setcoreidx(sih, coreid); ++ INTR_RESTORE(sii, intr_val); ++} ++ ++int ++si_numaddrspaces(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_numaddrspaces(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_numaddrspaces(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_numaddrspaces(sih); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++uint32 ++si_addrspace(si_t *sih, uint asidx) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_addrspace(sih, asidx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_addrspace(sih, asidx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_addrspace(sih, asidx); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++uint32 ++si_addrspacesize(si_t *sih, uint asidx) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_addrspacesize(sih, asidx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_addrspacesize(sih, asidx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_addrspacesize(sih, asidx); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++void ++si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) ++{ ++ /* Only supported for SOCI_AI */ ++ if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ ai_coreaddrspaceX(sih, asidx, addr, size); ++ else ++ *size = 0; ++} ++ ++uint32 ++si_core_cflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_core_cflags(sih, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_core_cflags(sih, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_core_cflags(sih, mask, val); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++void ++si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ sb_core_cflags_wo(sih, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ ai_core_cflags_wo(sih, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ ub_core_cflags_wo(sih, mask, val); ++ else ++ ASSERT(0); ++} ++ ++uint32 ++si_core_sflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_core_sflags(sih, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_core_sflags(sih, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_core_sflags(sih, mask, val); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++bool ++si_iscoreup(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_iscoreup(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_iscoreup(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_iscoreup(sih); ++ else { ++ ASSERT(0); ++ return FALSE; ++ } ++} ++ ++uint ++si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val) ++{ ++ /* only for AI back plane chips */ ++ if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return (ai_wrap_reg(sih, offset, mask, val)); ++ return 0; ++} ++ ++uint ++si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_corereg(sih, coreidx, regoff, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ return ai_corereg(sih, coreidx, regoff, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_corereg(sih, coreidx, regoff, mask, val); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++void ++si_core_disable(si_t *sih, uint32 bits) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ sb_core_disable(sih, bits); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ ai_core_disable(sih, bits); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ ub_core_disable(sih, bits); ++} ++ ++void ++si_core_reset(si_t *sih, uint32 bits, uint32 resetbits) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ sb_core_reset(sih, bits, resetbits); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI) ++ ai_core_reset(sih, bits, resetbits); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ ub_core_reset(sih, bits, resetbits); ++} ++ ++/* Run bist on current core. Caller needs to take care of core-specific bist hazards */ ++int ++si_corebist(si_t *sih) ++{ ++ uint32 cflags; ++ int result = 0; ++ ++ /* Read core control flags */ ++ cflags = si_core_cflags(sih, 0, 0); ++ ++ /* Set bist & fgc */ ++ si_core_cflags(sih, ~0, (SICF_BIST_EN | SICF_FGC)); ++ ++ /* Wait for bist done */ ++ SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000); ++ ++ if (si_core_sflags(sih, 0, 0) & SISF_BIST_ERROR) ++ result = BCME_ERROR; ++ ++ /* Reset core control flags */ ++ si_core_cflags(sih, 0xffff, cflags); ++ ++ return result; ++} ++ ++static uint32 ++factor6(uint32 x) ++{ ++ switch (x) { ++ case CC_F6_2: return 2; ++ case CC_F6_3: return 3; ++ case CC_F6_4: return 4; ++ case CC_F6_5: return 5; ++ case CC_F6_6: return 6; ++ case CC_F6_7: return 7; ++ default: return 0; ++ } ++} ++ ++/* calculate the speed the SI would run at given a set of clockcontrol values */ ++uint32 ++si_clock_rate(uint32 pll_type, uint32 n, uint32 m) ++{ ++ uint32 n1, n2, clock, m1, m2, m3, mc; ++ ++ n1 = n & CN_N1_MASK; ++ n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT; ++ ++ if (pll_type == PLL_TYPE6) { ++ if (m & CC_T6_MMASK) ++ return CC_T6_M1; ++ else ++ return CC_T6_M0; ++ } else if ((pll_type == PLL_TYPE1) || ++ (pll_type == PLL_TYPE3) || ++ (pll_type == PLL_TYPE4) || ++ (pll_type == PLL_TYPE7)) { ++ n1 = factor6(n1); ++ n2 += CC_F5_BIAS; ++ } else if (pll_type == PLL_TYPE2) { ++ n1 += CC_T2_BIAS; ++ n2 += CC_T2_BIAS; ++ ASSERT((n1 >= 2) && (n1 <= 7)); ++ ASSERT((n2 >= 5) && (n2 <= 23)); ++ } else if (pll_type == PLL_TYPE5) { ++ return (100000000); ++ } else ++ ASSERT(0); ++ /* PLL types 3 and 7 use BASE2 (25Mhz) */ ++ if ((pll_type == PLL_TYPE3) || ++ (pll_type == PLL_TYPE7)) { ++ clock = CC_CLOCK_BASE2 * n1 * n2; ++ } else ++ clock = CC_CLOCK_BASE1 * n1 * n2; ++ ++ if (clock == 0) ++ return 0; ++ ++ m1 = m & CC_M1_MASK; ++ m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT; ++ m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT; ++ mc = (m & CC_MC_MASK) >> CC_MC_SHIFT; ++ ++ if ((pll_type == PLL_TYPE1) || ++ (pll_type == PLL_TYPE3) || ++ (pll_type == PLL_TYPE4) || ++ (pll_type == PLL_TYPE7)) { ++ m1 = factor6(m1); ++ if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3)) ++ m2 += CC_F5_BIAS; ++ else ++ m2 = factor6(m2); ++ m3 = factor6(m3); ++ ++ switch (mc) { ++ case CC_MC_BYPASS: return (clock); ++ case CC_MC_M1: return (clock / m1); ++ case CC_MC_M1M2: return (clock / (m1 * m2)); ++ case CC_MC_M1M2M3: return (clock / (m1 * m2 * m3)); ++ case CC_MC_M1M3: return (clock / (m1 * m3)); ++ default: return (0); ++ } ++ } else { ++ ASSERT(pll_type == PLL_TYPE2); ++ ++ m1 += CC_T2_BIAS; ++ m2 += CC_T2M2_BIAS; ++ m3 += CC_T2_BIAS; ++ ASSERT((m1 >= 2) && (m1 <= 7)); ++ ASSERT((m2 >= 3) && (m2 <= 10)); ++ ASSERT((m3 >= 2) && (m3 <= 7)); ++ ++ if ((mc & CC_T2MC_M1BYP) == 0) ++ clock /= m1; ++ if ((mc & CC_T2MC_M2BYP) == 0) ++ clock /= m2; ++ if ((mc & CC_T2MC_M3BYP) == 0) ++ clock /= m3; ++ ++ return (clock); ++ } ++} ++ ++ ++/* set chip watchdog reset timer to fire in 'ticks' */ ++void ++si_watchdog(si_t *sih, uint ticks) ++{ ++ uint nb, maxt; ++ ++ if (PMUCTL_ENAB(sih)) { ++ ++ if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) && ++ (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) { ++ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), ~0, 0x2); ++ si_setcore(sih, USB20D_CORE_ID, 0); ++ si_core_disable(sih, 1); ++ si_setcore(sih, CC_CORE_ID, 0); ++ } ++ ++ nb = (sih->ccrev < 26) ? 16 : ((sih->ccrev >= 37) ? 32 : 24); ++ /* The mips compiler uses the sllv instruction, ++ * so we specially handle the 32-bit case. ++ */ ++ if (nb == 32) ++ maxt = 0xffffffff; ++ else ++ maxt = ((1 << nb) - 1); ++ ++ if (ticks == 1) ++ ticks = 2; ++ else if (ticks > maxt) ++ ticks = maxt; ++ ++ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, pmuwatchdog), ~0, ticks); ++ } else { ++ maxt = (1 << 28) - 1; ++ if (ticks > maxt) ++ ticks = maxt; ++ ++ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, ticks); ++ } ++} ++ ++/* trigger watchdog reset after ms milliseconds */ ++void ++si_watchdog_ms(si_t *sih, uint32 ms) ++{ ++ si_watchdog(sih, wd_msticks * ms); ++} ++ ++uint32 si_watchdog_msticks(void) ++{ ++ return wd_msticks; ++} ++ ++bool ++si_taclear(si_t *sih, bool details) ++{ ++ return FALSE; ++} ++ ++ ++ ++/* return the slow clock source - LPO, XTAL, or PCI */ ++static uint ++si_slowclk_src(si_info_t *sii) ++{ ++ chipcregs_t *cc; ++ ++ ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); ++ ++ if (sii->pub.ccrev < 6) { ++ if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) && ++ (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32)) & ++ PCI_CFG_GPIO_SCS)) ++ return (SCC_SS_PCI); ++ else ++ return (SCC_SS_XTAL); ++ } else if (sii->pub.ccrev < 10) { ++ cc = (chipcregs_t *)si_setcoreidx(&sii->pub, sii->curidx); ++ return (R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK); ++ } else /* Insta-clock */ ++ return (SCC_SS_XTAL); ++} ++ ++/* return the ILP (slowclock) min or max frequency */ ++static uint ++si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc) ++{ ++ uint32 slowclk; ++ uint div; ++ ++ ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); ++ ++ /* shouldn't be here unless we've established the chip has dynamic clk control */ ++ ASSERT(R_REG(sii->osh, &cc->capabilities) & CC_CAP_PWR_CTL); ++ ++ slowclk = si_slowclk_src(sii); ++ if (sii->pub.ccrev < 6) { ++ if (slowclk == SCC_SS_PCI) ++ return (max_freq ? (PCIMAXFREQ / 64) : (PCIMINFREQ / 64)); ++ else ++ return (max_freq ? (XTALMAXFREQ / 32) : (XTALMINFREQ / 32)); ++ } else if (sii->pub.ccrev < 10) { ++ div = 4 * ++ (((R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1); ++ if (slowclk == SCC_SS_LPO) ++ return (max_freq ? LPOMAXFREQ : LPOMINFREQ); ++ else if (slowclk == SCC_SS_XTAL) ++ return (max_freq ? (XTALMAXFREQ / div) : (XTALMINFREQ / div)); ++ else if (slowclk == SCC_SS_PCI) ++ return (max_freq ? (PCIMAXFREQ / div) : (PCIMINFREQ / div)); ++ else ++ ASSERT(0); ++ } else { ++ /* Chipc rev 10 is InstaClock */ ++ div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT; ++ div = 4 * (div + 1); ++ return (max_freq ? XTALMAXFREQ : (XTALMINFREQ / div)); ++ } ++ return (0); ++} ++ ++static void ++si_clkctl_setdelay(si_info_t *sii, void *chipcregs) ++{ ++ chipcregs_t *cc = (chipcregs_t *)chipcregs; ++ uint slowmaxfreq, pll_delay, slowclk; ++ uint pll_on_delay, fref_sel_delay; ++ ++ pll_delay = PLL_DELAY; ++ ++ /* If the slow clock is not sourced by the xtal then add the xtal_on_delay ++ * since the xtal will also be powered down by dynamic clk control logic. ++ */ ++ ++ slowclk = si_slowclk_src(sii); ++ if (slowclk != SCC_SS_XTAL) ++ pll_delay += XTAL_ON_DELAY; ++ ++ /* Starting with 4318 it is ILP that is used for the delays */ ++ slowmaxfreq = si_slowclk_freq(sii, (sii->pub.ccrev >= 10) ? FALSE : TRUE, cc); ++ ++ pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000; ++ fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000; ++ ++ W_REG(sii->osh, &cc->pll_on_delay, pll_on_delay); ++ W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay); ++} ++ ++/* initialize power control delay registers */ ++void ++si_clkctl_init(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx = 0; ++ chipcregs_t *cc; ++ bool fast; ++ ++ if (!CCCTL_ENAB(sih)) ++ return; ++ ++ sii = SI_INFO(sih); ++ fast = SI_FAST(sii); ++ if (!fast) { ++ origidx = sii->curidx; ++ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) ++ return; ++ } else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL) ++ return; ++ ASSERT(cc != NULL); ++ ++ /* set all Instaclk chip ILP to 1 MHz */ ++ if (sih->ccrev >= 10) ++ SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK, ++ (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); ++ ++ si_clkctl_setdelay(sii, (void *)(uintptr)cc); ++ ++ if (!fast) ++ si_setcoreidx(sih, origidx); ++} ++ ++ ++/* change logical "focus" to the gpio core for optimized access */ ++void * ++si_gpiosetcore(si_t *sih) ++{ ++ return (si_setcoreidx(sih, SI_CC_IDX)); ++} ++ ++/* ++ * mask & set gpiocontrol bits. ++ * If a gpiocontrol bit is set to 0, chipcommon controls the corresponding GPIO pin. ++ * If a gpiocontrol bit is set to 1, the GPIO pin is no longer a GPIO and becomes dedicated ++ * to some chip-specific purpose. ++ */ ++uint32 ++si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority) ++{ ++ uint regoff; ++ ++ regoff = 0; ++ ++ /* gpios could be shared on router platforms ++ * ignore reservation if it's high priority (e.g., test apps) ++ */ ++ if ((priority != GPIO_HI_PRIORITY) && ++ (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { ++ mask = priority ? (si_gpioreservation & mask) : ++ ((si_gpioreservation | mask) & ~(si_gpioreservation)); ++ val &= mask; ++ } ++ ++ regoff = OFFSETOF(chipcregs_t, gpiocontrol); ++ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); ++} ++ ++/* mask&set gpio output enable bits */ ++uint32 ++si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority) ++{ ++ uint regoff; ++ ++ regoff = 0; ++ ++ /* gpios could be shared on router platforms ++ * ignore reservation if it's high priority (e.g., test apps) ++ */ ++ if ((priority != GPIO_HI_PRIORITY) && ++ (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { ++ mask = priority ? (si_gpioreservation & mask) : ++ ((si_gpioreservation | mask) & ~(si_gpioreservation)); ++ val &= mask; ++ } ++ ++ regoff = OFFSETOF(chipcregs_t, gpioouten); ++ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); ++} ++ ++/* mask&set gpio output bits */ ++uint32 ++si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority) ++{ ++ uint regoff; ++ ++ regoff = 0; ++ ++ /* gpios could be shared on router platforms ++ * ignore reservation if it's high priority (e.g., test apps) ++ */ ++ if ((priority != GPIO_HI_PRIORITY) && ++ (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { ++ mask = priority ? (si_gpioreservation & mask) : ++ ((si_gpioreservation | mask) & ~(si_gpioreservation)); ++ val &= mask; ++ } ++ ++ regoff = OFFSETOF(chipcregs_t, gpioout); ++ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); ++} ++ ++/* reserve one gpio */ ++uint32 ++si_gpioreserve(si_t *sih, uint32 gpio_bitmask, uint8 priority) ++{ ++ /* only cores on SI_BUS share GPIO's and only applcation users need to ++ * reserve/release GPIO ++ */ ++ if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { ++ ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); ++ return 0xffffffff; ++ } ++ /* make sure only one bit is set */ ++ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { ++ ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); ++ return 0xffffffff; ++ } ++ ++ /* already reserved */ ++ if (si_gpioreservation & gpio_bitmask) ++ return 0xffffffff; ++ /* set reservation */ ++ si_gpioreservation |= gpio_bitmask; ++ ++ return si_gpioreservation; ++} ++ ++/* release one gpio */ ++/* ++ * releasing the gpio doesn't change the current value on the GPIO last write value ++ * persists till some one overwrites it ++ */ ++ ++uint32 ++si_gpiorelease(si_t *sih, uint32 gpio_bitmask, uint8 priority) ++{ ++ /* only cores on SI_BUS share GPIO's and only applcation users need to ++ * reserve/release GPIO ++ */ ++ if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { ++ ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); ++ return 0xffffffff; ++ } ++ /* make sure only one bit is set */ ++ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { ++ ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); ++ return 0xffffffff; ++ } ++ ++ /* already released */ ++ if (!(si_gpioreservation & gpio_bitmask)) ++ return 0xffffffff; ++ ++ /* clear reservation */ ++ si_gpioreservation &= ~gpio_bitmask; ++ ++ return si_gpioreservation; ++} ++ ++/* return the current gpioin register value */ ++uint32 ++si_gpioin(si_t *sih) ++{ ++ uint regoff; ++ ++ regoff = OFFSETOF(chipcregs_t, gpioin); ++ return (si_corereg(sih, SI_CC_IDX, regoff, 0, 0)); ++} ++ ++/* mask&set gpio interrupt polarity bits */ ++uint32 ++si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority) ++{ ++ uint regoff; ++ ++ /* gpios could be shared on router platforms */ ++ if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { ++ mask = priority ? (si_gpioreservation & mask) : ++ ((si_gpioreservation | mask) & ~(si_gpioreservation)); ++ val &= mask; ++ } ++ ++ regoff = OFFSETOF(chipcregs_t, gpiointpolarity); ++ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); ++} ++ ++/* mask&set gpio interrupt mask bits */ ++uint32 ++si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority) ++{ ++ uint regoff; ++ ++ /* gpios could be shared on router platforms */ ++ if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { ++ mask = priority ? (si_gpioreservation & mask) : ++ ((si_gpioreservation | mask) & ~(si_gpioreservation)); ++ val &= mask; ++ } ++ ++ regoff = OFFSETOF(chipcregs_t, gpiointmask); ++ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); ++} ++ ++/* assign the gpio to an led */ ++uint32 ++si_gpioled(si_t *sih, uint32 mask, uint32 val) ++{ ++ if (sih->ccrev < 16) ++ return 0xffffffff; ++ ++ /* gpio led powersave reg */ ++ return (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val)); ++} ++ ++/* mask&set gpio timer val */ ++uint32 ++si_gpiotimerval(si_t *sih, uint32 mask, uint32 gpiotimerval) ++{ ++ if (sih->ccrev < 16) ++ return 0xffffffff; ++ ++ return (si_corereg(sih, SI_CC_IDX, ++ OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval)); ++} ++ ++uint32 ++si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val) ++{ ++ uint offs; ++ ++ if (sih->ccrev < 20) ++ return 0xffffffff; ++ ++ offs = (updown ? OFFSETOF(chipcregs_t, gpiopulldown) : OFFSETOF(chipcregs_t, gpiopullup)); ++ return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); ++} ++ ++uint32 ++si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val) ++{ ++ uint offs; ++ ++ if (sih->ccrev < 11) ++ return 0xffffffff; ++ ++ if (regtype == GPIO_REGEVT) ++ offs = OFFSETOF(chipcregs_t, gpioevent); ++ else if (regtype == GPIO_REGEVT_INTMSK) ++ offs = OFFSETOF(chipcregs_t, gpioeventintmask); ++ else if (regtype == GPIO_REGEVT_INTPOL) ++ offs = OFFSETOF(chipcregs_t, gpioeventintpolarity); ++ else ++ return 0xffffffff; ++ ++ return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); ++} ++ ++void * ++si_gpio_handler_register(si_t *sih, uint32 event, ++ bool level, gpio_handler_t cb, void *arg) ++{ ++ si_info_t *sii; ++ gpioh_item_t *gi; ++ ++ ASSERT(event); ++ ASSERT(cb != NULL); ++ ++ sii = SI_INFO(sih); ++ if (sih->ccrev < 11) ++ return NULL; ++ ++ if ((gi = MALLOC(sii->osh, sizeof(gpioh_item_t))) == NULL) ++ return NULL; ++ ++ bzero(gi, sizeof(gpioh_item_t)); ++ gi->event = event; ++ gi->handler = cb; ++ gi->arg = arg; ++ gi->level = level; ++ ++ gi->next = sii->gpioh_head; ++ sii->gpioh_head = gi; ++ ++ return (void *)(gi); ++} ++ ++void ++si_gpio_handler_unregister(si_t *sih, void *gpioh) ++{ ++ si_info_t *sii; ++ gpioh_item_t *p, *n; ++ ++ sii = SI_INFO(sih); ++ if (sih->ccrev < 11) ++ return; ++ ++ ASSERT(sii->gpioh_head != NULL); ++ if ((void*)sii->gpioh_head == gpioh) { ++ sii->gpioh_head = sii->gpioh_head->next; ++ MFREE(sii->osh, gpioh, sizeof(gpioh_item_t)); ++ return; ++ } else { ++ p = sii->gpioh_head; ++ n = p->next; ++ while (n) { ++ if ((void*)n == gpioh) { ++ p->next = n->next; ++ MFREE(sii->osh, gpioh, sizeof(gpioh_item_t)); ++ return; ++ } ++ p = n; ++ n = n->next; ++ } ++ } ++ ++ ASSERT(0); /* Not found in list */ ++} ++ ++void ++si_gpio_handler_process(si_t *sih) ++{ ++ si_info_t *sii; ++ gpioh_item_t *h; ++ uint32 level = si_gpioin(sih); ++ uint32 levelp = si_gpiointpolarity(sih, 0, 0, 0); ++ uint32 edge = si_gpioevent(sih, GPIO_REGEVT, 0, 0); ++ uint32 edgep = si_gpioevent(sih, GPIO_REGEVT_INTPOL, 0, 0); ++ ++ sii = SI_INFO(sih); ++ for (h = sii->gpioh_head; h != NULL; h = h->next) { ++ if (h->handler) { ++ uint32 status = (h->level ? level : edge) & h->event; ++ uint32 polarity = (h->level ? levelp : edgep) & h->event; ++ ++ /* polarity bitval is opposite of status bitval */ ++ if (status ^ polarity) ++ h->handler(status, h->arg); ++ } ++ } ++ ++ si_gpioevent(sih, GPIO_REGEVT, edge, edge); /* clear edge-trigger status */ ++} ++ ++uint32 ++si_gpio_int_enable(si_t *sih, bool enable) ++{ ++ uint offs; ++ ++ if (sih->ccrev < 11) ++ return 0xffffffff; ++ ++ offs = OFFSETOF(chipcregs_t, intmask); ++ return (si_corereg(sih, SI_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0))); ++} ++ ++ ++/* Return the size of the specified SOCRAM bank */ ++static uint ++socram_banksize(si_info_t *sii, sbsocramregs_t *regs, uint8 idx, uint8 mem_type) ++{ ++ uint banksize, bankinfo; ++ uint bankidx = idx | (mem_type << SOCRAM_BANKIDX_MEMTYPE_SHIFT); ++ ++ ASSERT(mem_type <= SOCRAM_MEMTYPE_DEVRAM); ++ ++ W_REG(sii->osh, ®s->bankidx, bankidx); ++ bankinfo = R_REG(sii->osh, ®s->bankinfo); ++ banksize = SOCRAM_BANKINFO_SZBASE * ((bankinfo & SOCRAM_BANKINFO_SZMASK) + 1); ++ return banksize; ++} ++ ++void ++si_socdevram(si_t *sih, bool set, uint8 *enable, uint8 *protect, uint8 *remap) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ sbsocramregs_t *regs; ++ bool wasup; ++ uint corerev; ++ ++ sii = SI_INFO(sih); ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ if (!set) ++ *enable = *protect = *remap = 0; ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ ++ corerev = si_corerev(sih); ++ if (corerev >= 10) { ++ uint32 extcinfo; ++ uint8 nb; ++ uint8 i; ++ uint32 bankidx, bankinfo; ++ ++ extcinfo = R_REG(sii->osh, ®s->extracoreinfo); ++ nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); ++ for (i = 0; i < nb; i++) { ++ bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); ++ W_REG(sii->osh, ®s->bankidx, bankidx); ++ bankinfo = R_REG(sii->osh, ®s->bankinfo); ++ if (set) { ++ bankinfo &= ~SOCRAM_BANKINFO_DEVRAMSEL_MASK; ++ bankinfo &= ~SOCRAM_BANKINFO_DEVRAMPRO_MASK; ++ bankinfo &= ~SOCRAM_BANKINFO_DEVRAMREMAP_MASK; ++ if (*enable) { ++ bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMSEL_SHIFT); ++ if (*protect) ++ bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMPRO_SHIFT); ++ if ((corerev >= 16) && *remap) ++ bankinfo |= ++ (1 << SOCRAM_BANKINFO_DEVRAMREMAP_SHIFT); ++ } ++ W_REG(sii->osh, ®s->bankinfo, bankinfo); ++ } ++ else if (i == 0) { ++ if (bankinfo & SOCRAM_BANKINFO_DEVRAMSEL_MASK) { ++ *enable = 1; ++ if (bankinfo & SOCRAM_BANKINFO_DEVRAMPRO_MASK) ++ *protect = 1; ++ if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) ++ *remap = 1; ++ } ++ } ++ } ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++} ++ ++bool ++si_socdevram_remap_isenb(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ sbsocramregs_t *regs; ++ bool wasup, remap = FALSE; ++ uint corerev; ++ uint32 extcinfo; ++ uint8 nb; ++ uint8 i; ++ uint32 bankidx, bankinfo; ++ ++ sii = SI_INFO(sih); ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ ++ corerev = si_corerev(sih); ++ if (corerev >= 16) { ++ extcinfo = R_REG(sii->osh, ®s->extracoreinfo); ++ nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); ++ for (i = 0; i < nb; i++) { ++ bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); ++ W_REG(sii->osh, ®s->bankidx, bankidx); ++ bankinfo = R_REG(sii->osh, ®s->bankinfo); ++ if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) { ++ remap = TRUE; ++ break; ++ } ++ } ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ return remap; ++} ++ ++bool ++si_socdevram_pkg(si_t *sih) ++{ ++ if (si_socdevram_size(sih) > 0) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++uint32 ++si_socdevram_size(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ uint32 memsize = 0; ++ sbsocramregs_t *regs; ++ bool wasup; ++ uint corerev; ++ ++ sii = SI_INFO(sih); ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ ++ corerev = si_corerev(sih); ++ if (corerev >= 10) { ++ uint32 extcinfo; ++ uint8 nb; ++ uint8 i; ++ ++ extcinfo = R_REG(sii->osh, ®s->extracoreinfo); ++ nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); ++ for (i = 0; i < nb; i++) ++ memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ ++ return memsize; ++} ++ ++uint32 ++si_socdevram_remap_size(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ uint32 memsize = 0, banksz; ++ sbsocramregs_t *regs; ++ bool wasup; ++ uint corerev; ++ uint32 extcinfo; ++ uint8 nb; ++ uint8 i; ++ uint32 bankidx, bankinfo; ++ ++ sii = SI_INFO(sih); ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ ++ corerev = si_corerev(sih); ++ if (corerev >= 16) { ++ extcinfo = R_REG(sii->osh, ®s->extracoreinfo); ++ nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); ++ ++ /* ++ * FIX: A0 Issue: Max addressable is 512KB, instead 640KB ++ * Only four banks are accessible to ARM ++ */ ++ if ((corerev == 16) && (nb == 5)) ++ nb = 4; ++ ++ for (i = 0; i < nb; i++) { ++ bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); ++ W_REG(sii->osh, ®s->bankidx, bankidx); ++ bankinfo = R_REG(sii->osh, ®s->bankinfo); ++ if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) { ++ banksz = socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); ++ memsize += banksz; ++ } else { ++ /* Account only consecutive banks for now */ ++ break; ++ } ++ } ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ ++ return memsize; ++} ++ ++/* Return the RAM size of the SOCRAM core */ ++uint32 ++si_socram_size(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ ++ sbsocramregs_t *regs; ++ bool wasup; ++ uint corerev; ++ uint32 coreinfo; ++ uint memsize = 0; ++ ++ sii = SI_INFO(sih); ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ corerev = si_corerev(sih); ++ coreinfo = R_REG(sii->osh, ®s->coreinfo); ++ ++ /* Calculate size from coreinfo based on rev */ ++ if (corerev == 0) ++ memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK)); ++ else if (corerev < 3) { ++ memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK)); ++ memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; ++ } else if ((corerev <= 7) || (corerev == 12)) { ++ uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; ++ uint bsz = (coreinfo & SRCI_SRBSZ_MASK); ++ uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT; ++ if (lss != 0) ++ nb --; ++ memsize = nb * (1 << (bsz + SR_BSZ_BASE)); ++ if (lss != 0) ++ memsize += (1 << ((lss - 1) + SR_BSZ_BASE)); ++ } else { ++ uint8 i; ++ uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; ++ for (i = 0; i < nb; i++) ++ memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ ++ return memsize; ++} ++ ++ ++/* Return the TCM-RAM size of the ARMCR4 core. */ ++uint32 ++si_tcm_size(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ uint8 *regs; ++ bool wasup; ++ uint32 corecap; ++ uint memsize = 0; ++ uint32 nab = 0; ++ uint32 nbb = 0; ++ uint32 totb = 0; ++ uint32 bxinfo = 0; ++ uint32 idx = 0; ++ uint32 *arm_cap_reg; ++ uint32 *arm_bidx; ++ uint32 *arm_binfo; ++ ++ sii = SI_INFO(sih); ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to CR4 core */ ++ if (!(regs = si_setcore(sih, ARMCR4_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size. If in reset, come out of reset, ++ * but remain in halt ++ */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, SICF_CPUHALT, SICF_CPUHALT); ++ ++ arm_cap_reg = (uint32 *)(regs + SI_CR4_CAP); ++ corecap = R_REG(sii->osh, arm_cap_reg); ++ ++ nab = (corecap & ARMCR4_TCBANB_MASK) >> ARMCR4_TCBANB_SHIFT; ++ nbb = (corecap & ARMCR4_TCBBNB_MASK) >> ARMCR4_TCBBNB_SHIFT; ++ totb = nab + nbb; ++ ++ arm_bidx = (uint32 *)(regs + SI_CR4_BANKIDX); ++ arm_binfo = (uint32 *)(regs + SI_CR4_BANKINFO); ++ for (idx = 0; idx < totb; idx++) { ++ W_REG(sii->osh, arm_bidx, idx); ++ ++ bxinfo = R_REG(sii->osh, arm_binfo); ++ memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * ARMCR4_BSZ_MULT; ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ ++ return memsize; ++} ++ ++uint32 ++si_socram_srmem_size(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ ++ sbsocramregs_t *regs; ++ bool wasup; ++ uint corerev; ++ uint32 coreinfo; ++ uint memsize = 0; ++ ++ if ((CHIPID(sih->chip) == BCM4334_CHIP_ID) && (CHIPREV(sih->chiprev) < 2)) { ++ return (32 * 1024); ++ } ++ ++ sii = SI_INFO(sih); ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ corerev = si_corerev(sih); ++ coreinfo = R_REG(sii->osh, ®s->coreinfo); ++ ++ /* Calculate size from coreinfo based on rev */ ++ if (corerev >= 16) { ++ uint8 i; ++ uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; ++ for (i = 0; i < nb; i++) { ++ W_REG(sii->osh, ®s->bankidx, i); ++ if (R_REG(sii->osh, ®s->bankinfo) & SOCRAM_BANKINFO_RETNTRAM_MASK) ++ memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); ++ } ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ ++ return memsize; ++} ++ ++ ++void ++si_btcgpiowar(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx; ++ uint intr_val = 0; ++ chipcregs_t *cc; ++ ++ sii = SI_INFO(sih); ++ ++ /* Make sure that there is ChipCommon core present && ++ * UART_TX is strapped to 1 ++ */ ++ if (!(sih->cccaps & CC_CAP_UARTGPIO)) ++ return; ++ ++ /* si_corereg cannot be used as we have to guarantee 8-bit read/writes */ ++ INTR_OFF(sii, intr_val); ++ ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ASSERT(cc != NULL); ++ ++ W_REG(sii->osh, &cc->uart0mcr, R_REG(sii->osh, &cc->uart0mcr) | 0x04); ++ ++ /* restore the original index */ ++ si_setcoreidx(sih, origidx); ++ ++ INTR_RESTORE(sii, intr_val); ++} ++ ++void ++si_chipcontrl_btshd0_4331(si_t *sih, bool on) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ uint32 val; ++ uint intr_val = 0; ++ ++ sii = SI_INFO(sih); ++ ++ INTR_OFF(sii, intr_val); ++ ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ++ val = R_REG(sii->osh, &cc->chipcontrol); ++ ++ /* bt_shd0 controls are same for 4331 chiprevs 0 and 1, packages 12x9 and 12x12 */ ++ if (on) { ++ /* Enable bt_shd0 on gpio4: */ ++ val |= (CCTRL4331_BT_SHD0_ON_GPIO4); ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } else { ++ val &= ~(CCTRL4331_BT_SHD0_ON_GPIO4); ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } ++ ++ /* restore the original index */ ++ si_setcoreidx(sih, origidx); ++ ++ INTR_RESTORE(sii, intr_val); ++} ++ ++void ++si_chipcontrl_restore(si_t *sih, uint32 val) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ si_setcoreidx(sih, origidx); ++} ++ ++uint32 ++si_chipcontrl_read(si_t *sih) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ uint32 val; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ val = R_REG(sii->osh, &cc->chipcontrol); ++ si_setcoreidx(sih, origidx); ++ return val; ++} ++ ++void ++si_chipcontrl_epa4331(si_t *sih, bool on) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ uint32 val; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ++ val = R_REG(sii->osh, &cc->chipcontrol); ++ ++ if (on) { ++ if (sih->chippkg == 9 || sih->chippkg == 0xb) { ++ val |= (CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); ++ /* Ext PA Controls for 4331 12x9 Package */ ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } else { ++ /* Ext PA Controls for 4331 12x12 Package */ ++ if (sih->chiprev > 0) { ++ W_REG(sii->osh, &cc->chipcontrol, val | ++ (CCTRL4331_EXTPA_EN) | (CCTRL4331_EXTPA_EN2)); ++ } else { ++ W_REG(sii->osh, &cc->chipcontrol, val | (CCTRL4331_EXTPA_EN)); ++ } ++ } ++ } else { ++ val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_EN2 | CCTRL4331_EXTPA_ON_GPIO2_5); ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } ++ ++ si_setcoreidx(sih, origidx); ++} ++ ++/* switch muxed pins, on: SROM, off: FEMCTRL */ ++void ++si_chipcontrl_srom4360(si_t *sih, bool on) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ uint32 val; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ++ val = R_REG(sii->osh, &cc->chipcontrol); ++ ++ if (on) { ++ val &= ~(CCTRL4360_SECI_MODE | ++ CCTRL4360_BTSWCTRL_MODE | ++ CCTRL4360_EXTRA_FEMCTRL_MODE | ++ CCTRL4360_BT_LGCY_MODE | ++ CCTRL4360_CORE2FEMCTRL4_ON); ++ ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } else { ++ } ++ ++ si_setcoreidx(sih, origidx); ++} ++ ++void ++si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ uint32 val; ++ bool sel_chip; ++ ++ sel_chip = (CHIPID(sih->chip) == BCM4331_CHIP_ID) || ++ (CHIPID(sih->chip) == BCM43431_CHIP_ID); ++ sel_chip &= ((sih->chippkg == 9 || sih->chippkg == 0xb)); ++ ++ if (!sel_chip) ++ return; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ++ val = R_REG(sii->osh, &cc->chipcontrol); ++ ++ if (enter_wowl) { ++ val |= CCTRL4331_EXTPA_EN; ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } else { ++ val |= (CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } ++ si_setcoreidx(sih, origidx); ++} ++ ++uint ++si_pll_reset(si_t *sih) ++{ ++ uint err = 0; ++ ++ return (err); ++} ++ ++/* Enable BT-COEX & Ex-PA for 4313 */ ++void ++si_epa_4313war(si_t *sih) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ++ /* EPA Fix */ ++ W_REG(sii->osh, &cc->gpiocontrol, ++ R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK); ++ ++ si_setcoreidx(sih, origidx); ++} ++ ++void ++si_clk_pmu_htavail_set(si_t *sih, bool set_clear) ++{ ++} ++ ++/* WL/BT control for 4313 btcombo boards >= P250 */ ++void ++si_btcombo_p250_4313_war(si_t *sih) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ W_REG(sii->osh, &cc->gpiocontrol, ++ R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_5_6_EN_MASK); ++ ++ W_REG(sii->osh, &cc->gpioouten, ++ R_REG(sii->osh, &cc->gpioouten) | GPIO_CTRL_5_6_EN_MASK); ++ ++ si_setcoreidx(sih, origidx); ++} ++void ++si_btc_enable_chipcontrol(si_t *sih) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ++ /* BT fix */ ++ W_REG(sii->osh, &cc->chipcontrol, ++ R_REG(sii->osh, &cc->chipcontrol) | CC_BTCOEX_EN_MASK); ++ ++ si_setcoreidx(sih, origidx); ++} ++void ++si_btcombo_43228_war(si_t *sih) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ++ W_REG(sii->osh, &cc->gpioouten, GPIO_CTRL_7_6_EN_MASK); ++ W_REG(sii->osh, &cc->gpioout, GPIO_OUT_7_EN_MASK); ++ ++ si_setcoreidx(sih, origidx); ++} ++ ++/* check if the device is removed */ ++bool ++si_deviceremoved(si_t *sih) ++{ ++ uint32 w; ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ switch (BUSTYPE(sih->bustype)) { ++ case PCI_BUS: ++ ASSERT(sii->osh != NULL); ++ w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_VID, sizeof(uint32)); ++ if ((w & 0xFFFF) != VENDOR_BROADCOM) ++ return TRUE; ++ break; ++ } ++ return FALSE; ++} ++ ++bool ++si_is_sprom_available(si_t *sih) ++{ ++ if (sih->ccrev >= 31) { ++ si_info_t *sii; ++ uint origidx; ++ chipcregs_t *cc; ++ uint32 sromctrl; ++ ++ if ((sih->cccaps & CC_CAP_SROM) == 0) ++ return FALSE; ++ ++ sii = SI_INFO(sih); ++ origidx = sii->curidx; ++ cc = si_setcoreidx(sih, SI_CC_IDX); ++ sromctrl = R_REG(sii->osh, &cc->sromcontrol); ++ si_setcoreidx(sih, origidx); ++ return (sromctrl & SRC_PRESENT); ++ } ++ ++ switch (CHIPID(sih->chip)) { ++ case BCM4312_CHIP_ID: ++ return ((sih->chipst & CST4312_SPROM_OTP_SEL_MASK) != CST4312_OTP_SEL); ++ case BCM4325_CHIP_ID: ++ return (sih->chipst & CST4325_SPROM_SEL) != 0; ++ case BCM4322_CHIP_ID: case BCM43221_CHIP_ID: case BCM43231_CHIP_ID: ++ case BCM43222_CHIP_ID: case BCM43111_CHIP_ID: case BCM43112_CHIP_ID: ++ case BCM4342_CHIP_ID: { ++ uint32 spromotp; ++ spromotp = (sih->chipst & CST4322_SPROM_OTP_SEL_MASK) >> ++ CST4322_SPROM_OTP_SEL_SHIFT; ++ return (spromotp & CST4322_SPROM_PRESENT) != 0; ++ } ++ case BCM4329_CHIP_ID: ++ return (sih->chipst & CST4329_SPROM_SEL) != 0; ++ case BCM4315_CHIP_ID: ++ return (sih->chipst & CST4315_SPROM_SEL) != 0; ++ case BCM4319_CHIP_ID: ++ return (sih->chipst & CST4319_SPROM_SEL) != 0; ++ case BCM4336_CHIP_ID: ++ case BCM43362_CHIP_ID: ++ return (sih->chipst & CST4336_SPROM_PRESENT) != 0; ++ case BCM4330_CHIP_ID: ++ return (sih->chipst & CST4330_SPROM_PRESENT) != 0; ++ case BCM4313_CHIP_ID: ++ return (sih->chipst & CST4313_SPROM_PRESENT) != 0; ++ case BCM4331_CHIP_ID: ++ case BCM43431_CHIP_ID: ++ return (sih->chipst & CST4331_SPROM_PRESENT) != 0; ++ case BCM43239_CHIP_ID: ++ return ((sih->chipst & CST43239_SPROM_MASK) && ++ !(sih->chipst & CST43239_SFLASH_MASK)); ++ case BCM4324_CHIP_ID: ++ return ((sih->chipst & CST4324_SPROM_MASK) && ++ !(sih->chipst & CST4324_SFLASH_MASK)); ++ case BCM4335_CHIP_ID: ++ return ((sih->chipst & CST4335_SPROM_MASK) && ++ !(sih->chipst & CST4335_SFLASH_MASK)); ++ case BCM43131_CHIP_ID: ++ case BCM43217_CHIP_ID: ++ case BCM43227_CHIP_ID: ++ case BCM43228_CHIP_ID: ++ case BCM43428_CHIP_ID: ++ return (sih->chipst & CST43228_OTP_PRESENT) != CST43228_OTP_PRESENT; ++ default: ++ return TRUE; ++ } ++} ++ ++ ++uint32 si_get_sromctl(si_t *sih) ++{ ++ chipcregs_t *cc; ++ uint origidx; ++ uint32 sromctl; ++ osl_t *osh; ++ ++ osh = si_osh(sih); ++ origidx = si_coreidx(sih); ++ cc = si_setcoreidx(sih, SI_CC_IDX); ++ ASSERT((uintptr)cc); ++ ++ sromctl = R_REG(osh, &cc->sromcontrol); ++ ++ /* return to the original core */ ++ si_setcoreidx(sih, origidx); ++ return sromctl; ++} ++ ++int si_set_sromctl(si_t *sih, uint32 value) ++{ ++ chipcregs_t *cc; ++ uint origidx; ++ osl_t *osh; ++ ++ osh = si_osh(sih); ++ origidx = si_coreidx(sih); ++ cc = si_setcoreidx(sih, SI_CC_IDX); ++ ASSERT((uintptr)cc); ++ ++ /* get chipcommon rev */ ++ if (si_corerev(sih) < 32) ++ return BCME_UNSUPPORTED; ++ ++ W_REG(osh, &cc->sromcontrol, value); ++ ++ /* return to the original core */ ++ si_setcoreidx(sih, origidx); ++ return BCME_OK; ++ ++} +diff --git a/drivers/net/wireless/ap6211/siutils_priv.h b/drivers/net/wireless/ap6211/siutils_priv.h +new file mode 100755 +index 0000000..34fc3fa +--- /dev/null ++++ b/drivers/net/wireless/ap6211/siutils_priv.h +@@ -0,0 +1,236 @@ ++/* ++ * Include file private to the SOC Interconnect support files. ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: siutils_priv.h 309193 2012-01-19 00:03:57Z $ ++ */ ++ ++#ifndef _siutils_priv_h_ ++#define _siutils_priv_h_ ++ ++#define IS_SIM(chippkg) ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) ++ ++typedef uint32 (*si_intrsoff_t)(void *intr_arg); ++typedef void (*si_intrsrestore_t)(void *intr_arg, uint32 arg); ++typedef bool (*si_intrsenabled_t)(void *intr_arg); ++ ++typedef struct gpioh_item { ++ void *arg; ++ bool level; ++ gpio_handler_t handler; ++ uint32 event; ++ struct gpioh_item *next; ++} gpioh_item_t; ++ ++/* misc si info needed by some of the routines */ ++typedef struct si_info { ++ struct si_pub pub; /* back plane public state (must be first field) */ ++ ++ void *osh; /* osl os handle */ ++ void *sdh; /* bcmsdh handle */ ++ ++ uint dev_coreid; /* the core provides driver functions */ ++ void *intr_arg; /* interrupt callback function arg */ ++ si_intrsoff_t intrsoff_fn; /* turns chip interrupts off */ ++ si_intrsrestore_t intrsrestore_fn; /* restore chip interrupts */ ++ si_intrsenabled_t intrsenabled_fn; /* check if interrupts are enabled */ ++ ++ void *pch; /* PCI/E core handle */ ++ ++ gpioh_item_t *gpioh_head; /* GPIO event handlers list */ ++ ++ bool memseg; /* flag to toggle MEM_SEG register */ ++ ++ char *vars; ++ uint varsz; ++ ++ void *curmap; /* current regs va */ ++ void *regs[SI_MAXCORES]; /* other regs va */ ++ ++ uint curidx; /* current core index */ ++ uint numcores; /* # discovered cores */ ++ uint coreid[SI_MAXCORES]; /* id of each core */ ++ uint32 coresba[SI_MAXCORES]; /* backplane address of each core */ ++ void *regs2[SI_MAXCORES]; /* va of each core second register set (usbh20) */ ++ uint32 coresba2[SI_MAXCORES]; /* address of each core second register set (usbh20) */ ++ uint32 coresba_size[SI_MAXCORES]; /* backplane address space size */ ++ uint32 coresba2_size[SI_MAXCORES]; /* second address space size */ ++ ++ void *curwrap; /* current wrapper va */ ++ void *wrappers[SI_MAXCORES]; /* other cores wrapper va */ ++ uint32 wrapba[SI_MAXCORES]; /* address of controlling wrapper */ ++ ++ uint32 cia[SI_MAXCORES]; /* erom cia entry for each core */ ++ uint32 cib[SI_MAXCORES]; /* erom cia entry for each core */ ++ uint32 oob_router; /* oob router registers for axi */ ++} si_info_t; ++ ++#define SI_INFO(sih) (si_info_t *)(uintptr)sih ++ ++#define GOODCOREADDR(x, b) (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \ ++ ISALIGNED((x), SI_CORE_SIZE)) ++#define GOODREGS(regs) ((regs) != NULL && ISALIGNED((uintptr)(regs), SI_CORE_SIZE)) ++#define BADCOREADDR 0 ++#define GOODIDX(idx) (((uint)idx) < SI_MAXCORES) ++#define NOREV -1 /* Invalid rev */ ++ ++#define PCI(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ ++ ((si)->pub.buscoretype == PCI_CORE_ID)) ++ ++#define PCIE_GEN1(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ ++ ((si)->pub.buscoretype == PCIE_CORE_ID)) ++ ++#define PCIE_GEN2(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ ++ ((si)->pub.buscoretype == PCIE2_CORE_ID)) ++ ++#define PCIE(si) (PCIE_GEN1(si) || PCIE_GEN2(si)) ++ ++#define PCMCIA(si) ((BUSTYPE((si)->pub.bustype) == PCMCIA_BUS) && ((si)->memseg == TRUE)) ++ ++/* Newer chips can access PCI/PCIE and CC core without requiring to change ++ * PCI BAR0 WIN ++ */ ++#define SI_FAST(si) (PCIE(si) || (PCI(si) && ((si)->pub.buscorerev >= 13))) ++ ++#define PCIEREGS(si) (((char *)((si)->curmap) + PCI_16KB0_PCIREGS_OFFSET)) ++#define CCREGS_FAST(si) (((char *)((si)->curmap) + PCI_16KB0_CCREGS_OFFSET)) ++ ++/* ++ * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts before/ ++ * after core switching to avoid invalid register accesss inside ISR. ++ */ ++#define INTR_OFF(si, intr_val) \ ++ if ((si)->intrsoff_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \ ++ intr_val = (*(si)->intrsoff_fn)((si)->intr_arg); } ++#define INTR_RESTORE(si, intr_val) \ ++ if ((si)->intrsrestore_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \ ++ (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); } ++ ++/* dynamic clock control defines */ ++#define LPOMINFREQ 25000 /* low power oscillator min */ ++#define LPOMAXFREQ 43000 /* low power oscillator max */ ++#define XTALMINFREQ 19800000 /* 20 MHz - 1% */ ++#define XTALMAXFREQ 20200000 /* 20 MHz + 1% */ ++#define PCIMINFREQ 25000000 /* 25 MHz */ ++#define PCIMAXFREQ 34000000 /* 33 MHz + fudge */ ++ ++#define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */ ++#define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */ ++ ++#define PCI_FORCEHT(si) \ ++ (((PCIE_GEN1(si)) && (si->pub.chip == BCM4311_CHIP_ID) && ((si->pub.chiprev <= 1))) || \ ++ ((PCI(si) || PCIE_GEN1(si)) && (si->pub.chip == BCM4321_CHIP_ID)) || \ ++ (PCIE_GEN1(si) && (si->pub.chip == BCM4716_CHIP_ID)) || \ ++ (PCIE_GEN1(si) && (si->pub.chip == BCM4748_CHIP_ID))) ++ ++/* GPIO Based LED powersave defines */ ++#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */ ++#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */ ++ ++#ifndef DEFAULT_GPIOTIMERVAL ++#define DEFAULT_GPIOTIMERVAL ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME) ++#endif ++ ++/* Silicon Backplane externs */ ++extern void sb_scan(si_t *sih, void *regs, uint devid); ++extern uint sb_coreid(si_t *sih); ++extern uint sb_intflag(si_t *sih); ++extern uint sb_flag(si_t *sih); ++extern void sb_setint(si_t *sih, int siflag); ++extern uint sb_corevendor(si_t *sih); ++extern uint sb_corerev(si_t *sih); ++extern uint sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); ++extern bool sb_iscoreup(si_t *sih); ++extern void *sb_setcoreidx(si_t *sih, uint coreidx); ++extern uint32 sb_core_cflags(si_t *sih, uint32 mask, uint32 val); ++extern void sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); ++extern uint32 sb_core_sflags(si_t *sih, uint32 mask, uint32 val); ++extern void sb_commit(si_t *sih); ++extern uint32 sb_base(uint32 admatch); ++extern uint32 sb_size(uint32 admatch); ++extern void sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits); ++extern void sb_core_disable(si_t *sih, uint32 bits); ++extern uint32 sb_addrspace(si_t *sih, uint asidx); ++extern uint32 sb_addrspacesize(si_t *sih, uint asidx); ++extern int sb_numaddrspaces(si_t *sih); ++ ++extern uint32 sb_set_initiator_to(si_t *sih, uint32 to, uint idx); ++ ++extern bool sb_taclear(si_t *sih, bool details); ++ ++ ++/* Wake-on-wireless-LAN (WOWL) */ ++extern bool sb_pci_pmecap(si_t *sih); ++struct osl_info; ++extern bool sb_pci_fastpmecap(struct osl_info *osh); ++extern bool sb_pci_pmeclr(si_t *sih); ++extern void sb_pci_pmeen(si_t *sih); ++extern uint sb_pcie_readreg(void *sih, uint addrtype, uint offset); ++ ++/* AMBA Interconnect exported externs */ ++extern si_t *ai_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, ++ void *sdh, char **vars, uint *varsz); ++extern si_t *ai_kattach(osl_t *osh); ++extern void ai_scan(si_t *sih, void *regs, uint devid); ++ ++extern uint ai_flag(si_t *sih); ++extern void ai_setint(si_t *sih, int siflag); ++extern uint ai_coreidx(si_t *sih); ++extern uint ai_corevendor(si_t *sih); ++extern uint ai_corerev(si_t *sih); ++extern bool ai_iscoreup(si_t *sih); ++extern void *ai_setcoreidx(si_t *sih, uint coreidx); ++extern uint32 ai_core_cflags(si_t *sih, uint32 mask, uint32 val); ++extern void ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); ++extern uint32 ai_core_sflags(si_t *sih, uint32 mask, uint32 val); ++extern uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); ++extern void ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits); ++extern void ai_core_disable(si_t *sih, uint32 bits); ++extern int ai_numaddrspaces(si_t *sih); ++extern uint32 ai_addrspace(si_t *sih, uint asidx); ++extern uint32 ai_addrspacesize(si_t *sih, uint asidx); ++extern void ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); ++extern uint ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val); ++ ++ ++ ++#define ub_scan(a, b, c) do {} while (0) ++#define ub_flag(a) (0) ++#define ub_setint(a, b) do {} while (0) ++#define ub_coreidx(a) (0) ++#define ub_corevendor(a) (0) ++#define ub_corerev(a) (0) ++#define ub_iscoreup(a) (0) ++#define ub_setcoreidx(a, b) (0) ++#define ub_core_cflags(a, b, c) (0) ++#define ub_core_cflags_wo(a, b, c) do {} while (0) ++#define ub_core_sflags(a, b, c) (0) ++#define ub_corereg(a, b, c, d, e) (0) ++#define ub_core_reset(a, b, c) do {} while (0) ++#define ub_core_disable(a, b) do {} while (0) ++#define ub_numaddrspaces(a) (0) ++#define ub_addrspace(a, b) (0) ++#define ub_addrspacesize(a, b) (0) ++#define ub_view(a, b) do {} while (0) ++#define ub_dumpregs(a, b) do {} while (0) ++ ++#endif /* _siutils_priv_h_ */ +diff --git a/drivers/net/wireless/ap6211/uamp_api.h b/drivers/net/wireless/ap6211/uamp_api.h +new file mode 100755 +index 0000000..673dce0 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/uamp_api.h +@@ -0,0 +1,176 @@ ++/* ++ * Name: uamp_api.h ++ * ++ * Description: Universal AMP API ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: uamp_api.h 294267 2011-11-04 23:41:52Z $ ++ * ++ */ ++#ifndef UAMP_API_H ++#define UAMP_API_H ++ ++ ++#include "typedefs.h" ++ ++ ++/***************************************************************************** ++** Constant and Type Definitions ++****************************************************************************** ++*/ ++ ++#define BT_API ++ ++/* Types. */ ++typedef bool BOOLEAN; ++typedef uint8 UINT8; ++typedef uint16 UINT16; ++ ++ ++/* UAMP identifiers */ ++#define UAMP_ID_1 1 ++#define UAMP_ID_2 2 ++typedef UINT8 tUAMP_ID; ++ ++/* UAMP event ids (used by UAMP_CBACK) */ ++#define UAMP_EVT_RX_READY 0 /* Data from AMP controller is ready to be read */ ++#define UAMP_EVT_CTLR_REMOVED 1 /* Controller removed */ ++#define UAMP_EVT_CTLR_READY 2 /* Controller added/ready */ ++typedef UINT8 tUAMP_EVT; ++ ++ ++/* UAMP Channels */ ++#define UAMP_CH_HCI_CMD 0 /* HCI Command channel */ ++#define UAMP_CH_HCI_EVT 1 /* HCI Event channel */ ++#define UAMP_CH_HCI_DATA 2 /* HCI ACL Data channel */ ++typedef UINT8 tUAMP_CH; ++ ++/* tUAMP_EVT_DATA: union for event-specific data, used by UAMP_CBACK */ ++typedef union { ++ tUAMP_CH channel; /* UAMP_EVT_RX_READY: channel for which rx occured */ ++} tUAMP_EVT_DATA; ++ ++ ++/***************************************************************************** ++** ++** Function: UAMP_CBACK ++** ++** Description: Callback for events. Register callback using UAMP_Init. ++** ++** Parameters amp_id: AMP device identifier that generated the event ++** amp_evt: event id ++** p_amp_evt_data: pointer to event-specific data ++** ++****************************************************************************** ++*/ ++typedef void (*tUAMP_CBACK)(tUAMP_ID amp_id, tUAMP_EVT amp_evt, tUAMP_EVT_DATA *p_amp_evt_data); ++ ++/***************************************************************************** ++** external function declarations ++****************************************************************************** ++*/ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++/***************************************************************************** ++** ++** Function: UAMP_Init ++** ++** Description: Initialize UAMP driver ++** ++** Parameters p_cback: Callback function for UAMP event notification ++** ++****************************************************************************** ++*/ ++BT_API BOOLEAN UAMP_Init(tUAMP_CBACK p_cback); ++ ++ ++/***************************************************************************** ++** ++** Function: UAMP_Open ++** ++** Description: Open connection to local AMP device. ++** ++** Parameters app_id: Application specific AMP identifer. This value ++** will be included in AMP messages sent to the ++** BTU task, to identify source of the message ++** ++****************************************************************************** ++*/ ++BT_API BOOLEAN UAMP_Open(tUAMP_ID amp_id); ++ ++/***************************************************************************** ++** ++** Function: UAMP_Close ++** ++** Description: Close connection to local AMP device. ++** ++** Parameters app_id: Application specific AMP identifer. ++** ++****************************************************************************** ++*/ ++BT_API void UAMP_Close(tUAMP_ID amp_id); ++ ++ ++/***************************************************************************** ++** ++** Function: UAMP_Write ++** ++** Description: Send buffer to AMP device. Frees GKI buffer when done. ++** ++** ++** Parameters: app_id: AMP identifer. ++** p_buf: pointer to buffer to write ++** num_bytes: number of bytes to write ++** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_CMD ++** ++** Returns: number of bytes written ++** ++****************************************************************************** ++*/ ++BT_API UINT16 UAMP_Write(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 num_bytes, tUAMP_CH channel); ++ ++/***************************************************************************** ++** ++** Function: UAMP_Read ++** ++** Description: Read incoming data from AMP. Call after receiving a ++** UAMP_EVT_RX_READY callback event. ++** ++** Parameters: app_id: AMP identifer. ++** p_buf: pointer to buffer for holding incoming AMP data ++** buf_size: size of p_buf ++** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_EVT ++** ++** Returns: number of bytes read ++** ++****************************************************************************** ++*/ ++BT_API UINT16 UAMP_Read(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 buf_size, tUAMP_CH channel); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* UAMP_API_H */ +diff --git a/drivers/net/wireless/ap6211/wl_android.c b/drivers/net/wireless/ap6211/wl_android.c +new file mode 100755 +index 0000000..7e8b724 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_android.c +@@ -0,0 +1,1448 @@ ++/* ++ * Linux cfg80211 driver - Android related functions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_android.c 372668 2012-12-04 14:07:12Z $ ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef WL_CFG80211 ++#include ++#endif ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++#include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) ++#include ++#else ++#include ++#endif ++#endif /* CONFIG_WIFI_CONTROL_FUNC */ ++ ++#include ++ ++#ifndef WL_CFG80211 ++#define htod32(i) i ++#define htod16(i) i ++#define dtoh32(i) i ++#define dtoh16(i) i ++#define htodchanspec(i) i ++#define dtohchanspec(i) i ++#endif ++ ++/* ++ * Android private command strings, PLEASE define new private commands here ++ * so they can be updated easily in the future (if needed) ++ */ ++ ++#define CMD_START "START" ++#define CMD_STOP "STOP" ++#define CMD_SCAN_ACTIVE "SCAN-ACTIVE" ++#define CMD_SCAN_PASSIVE "SCAN-PASSIVE" ++#define CMD_RSSI "RSSI" ++#define CMD_LINKSPEED "LINKSPEED" ++#define CMD_RXFILTER_START "RXFILTER-START" ++#define CMD_RXFILTER_STOP "RXFILTER-STOP" ++#define CMD_RXFILTER_ADD "RXFILTER-ADD" ++#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE" ++#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START" ++#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" ++#define CMD_BTCOEXMODE "BTCOEXMODE" ++#define CMD_SETSUSPENDOPT "SETSUSPENDOPT" ++#define CMD_SETSUSPENDMODE "SETSUSPENDMODE" ++#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" ++#define CMD_SETFWPATH "SETFWPATH" ++#define CMD_SETBAND "SETBAND" ++#define CMD_GETBAND "GETBAND" ++#define CMD_COUNTRY "COUNTRY" ++#define CMD_P2P_SET_NOA "P2P_SET_NOA" ++#if !defined WL_ENABLE_P2P_IF ++#define CMD_P2P_GET_NOA "P2P_GET_NOA" ++#endif ++#define CMD_P2P_SD_OFFLOAD "P2P_SD_" ++#define CMD_P2P_SET_PS "P2P_SET_PS" ++#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" ++#define CMD_SETROAMMODE "SETROAMMODE" ++ ++ ++/* CCX Private Commands */ ++ ++#ifdef PNO_SUPPORT ++#define CMD_PNOSSIDCLR_SET "PNOSSIDCLR" ++#define CMD_PNOSETUP_SET "PNOSETUP " ++#define CMD_PNOENABLE_SET "PNOFORCE" ++#define CMD_PNODEBUG_SET "PNODEBUG" ++ ++#define PNO_TLV_PREFIX 'S' ++#define PNO_TLV_VERSION '1' ++#define PNO_TLV_SUBVERSION '2' ++#define PNO_TLV_RESERVED '0' ++#define PNO_TLV_TYPE_SSID_IE 'S' ++#define PNO_TLV_TYPE_TIME 'T' ++#define PNO_TLV_FREQ_REPEAT 'R' ++#define PNO_TLV_FREQ_EXPO_MAX 'M' ++ ++typedef struct cmd_tlv { ++ char prefix; ++ char version; ++ char subver; ++ char reserved; ++} cmd_tlv_t; ++#endif /* PNO_SUPPORT */ ++ ++#define CMD_OKC_SET_PMK "SET_PMK" ++#define CMD_OKC_ENABLE "OKC_ENABLE" ++ ++ ++typedef struct android_wifi_priv_cmd { ++ char *buf; ++ int used_len; ++ int total_len; ++} android_wifi_priv_cmd; ++ ++/** ++ * Extern function declarations (TODO: move them to dhd_linux.h) ++ */ ++void dhd_customer_gpio_wlan_ctrl(int onoff); ++int dhd_dev_reset(struct net_device *dev, uint8 flag); ++int dhd_dev_init_ioctl(struct net_device *dev); ++#ifdef WL_CFG80211 ++int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); ++int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command); ++#else ++int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) ++{ return 0; } ++int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) ++{ return 0; } ++int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) ++{ return 0; } ++int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) ++{ return 0; } ++#endif /* WL_CFG80211 */ ++ ++extern int dhd_os_check_wakelock(void *dhdp); ++extern int dhd_os_check_if_up(void *dhdp); ++extern void *bcmsdh_get_drvdata(void); ++#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB) ++extern int dhd_wlfc_init(dhd_pub_t *dhd); ++extern void dhd_wlfc_deinit(dhd_pub_t *dhd); ++#endif ++ ++extern bool ap_fw_loaded; ++extern char iface_name[IFNAMSIZ]; ++ ++#define WIFI_TURNOFF_DELAY 0 ++/** ++ * Local (static) functions and variables ++ */ ++ ++/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first ++ * time (only) in dhd_open, subsequential wifi on will be handled by ++ * wl_android_wifi_on ++ */ ++static int g_wifi_on = TRUE; ++ ++/** ++ * Local (static) function definitions ++ */ ++static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len) ++{ ++ int link_speed; ++ int bytes_written; ++ int error; ++ ++ error = wldev_get_link_speed(net, &link_speed); ++ if (error) ++ return -1; ++ ++ /* Convert Kbps to Android Mbps */ ++ link_speed = link_speed / 1000; ++ bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed); ++ AP6211_DEBUG("%s: command result is %s\n", __FUNCTION__, command); ++ return bytes_written; ++} ++ ++static int wl_android_get_rssi(struct net_device *net, char *command, int total_len) ++{ ++ wlc_ssid_t ssid = {0}; ++ int rssi; ++ int bytes_written = 0; ++ int error; ++ ++ error = wldev_get_rssi(net, &rssi); ++ if (error) ++ return -1; ++#if defined(RSSIOFFSET) ++ rssi = wl_update_rssi_offset(rssi); ++#endif ++ ++ error = wldev_get_ssid(net, &ssid); ++ if (error) ++ return -1; ++ if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) { ++ AP6211_ERR("%s: wldev_get_ssid failed\n", __FUNCTION__); ++ } else { ++ memcpy(command, ssid.SSID, ssid.SSID_len); ++ bytes_written = ssid.SSID_len; ++ } ++ bytes_written += snprintf(&command[bytes_written], total_len, " rssi %d", rssi); ++ AP6211_DEBUG("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written); ++ return bytes_written; ++} ++ ++static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len) ++{ ++ int suspend_flag; ++ int ret_now; ++ int ret = 0; ++ ++ suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0'; ++ ++ if (suspend_flag != 0) ++ suspend_flag = 1; ++ ret_now = net_os_set_suspend_disable(dev, suspend_flag); ++ ++ if (ret_now != suspend_flag) { ++ if (!(ret = net_os_set_suspend(dev, ret_now, 1))) ++ AP6211_DEBUG("%s: Suspend Flag %d -> %d\n", ++ __FUNCTION__, ret_now, suspend_flag); ++ else ++ AP6211_ERR("%s: failed %d\n", __FUNCTION__, ret); ++ } ++ return ret; ++} ++ ++static int wl_android_set_suspendmode(struct net_device *dev, char *command, int total_len) ++{ ++ int ret = 0; ++ ++#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND) ++ int suspend_flag; ++ ++ suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0'; ++ ++ if (suspend_flag != 0) ++ suspend_flag = 1; ++ ++ if (!(ret = net_os_set_suspend(dev, suspend_flag, 0))) ++ AP6211_DEBUG("%s: Suspend Mode %d\n",__FUNCTION__,suspend_flag); ++ else ++ AP6211_ERR("%s: failed %d\n",__FUNCTION__,ret); ++#endif ++ return ret; ++} ++ ++static int wl_android_get_band(struct net_device *dev, char *command, int total_len) ++{ ++ uint band; ++ int bytes_written; ++ int error; ++ ++ error = wldev_get_band(dev, &band); ++ if (error) ++ return -1; ++ bytes_written = snprintf(command, total_len, "Band %d", band); ++ return bytes_written; ++} ++ ++#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN) ++static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len) ++{ ++ wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; ++ int res = -1; ++ int nssid = 0; ++ cmd_tlv_t *cmd_tlv_temp; ++ char *str_ptr; ++ int tlv_size_left; ++ int pno_time = 0; ++ int pno_repeat = 0; ++ int pno_freq_expo_max = 0; ++ ++#ifdef PNO_SET_DEBUG ++ int i; ++ char pno_in_example[] = { ++ 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ', ++ 'S', '1', '2', '0', ++ 'S', ++ 0x05, ++ 'd', 'l', 'i', 'n', 'k', ++ 'S', ++ 0x04, ++ 'G', 'O', 'O', 'G', ++ 'T', ++ '0', 'B', ++ 'R', ++ '2', ++ 'M', ++ '2', ++ 0x00 ++ }; ++#endif /* PNO_SET_DEBUG */ ++ ++ AP6211_DEBUG("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len); ++ ++ if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) { ++ AP6211_ERR("%s argument=%d less min size\n", __FUNCTION__, total_len); ++ goto exit_proc; ++ } ++ ++ ++#ifdef PNO_SET_DEBUG ++ memcpy(command, pno_in_example, sizeof(pno_in_example)); ++ for (i = 0; i < sizeof(pno_in_example); i++) ++ AP6211_DUMP("%02X ", command[i]); ++ AP6211_DUMP("\n"); ++ total_len = sizeof(pno_in_example); ++#endif ++ ++ str_ptr = command + strlen(CMD_PNOSETUP_SET); ++ tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET); ++ ++ cmd_tlv_temp = (cmd_tlv_t *)str_ptr; ++ memset(ssids_local, 0, sizeof(ssids_local)); ++ ++ if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && ++ (cmd_tlv_temp->version == PNO_TLV_VERSION) && ++ (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) { ++ ++ str_ptr += sizeof(cmd_tlv_t); ++ tlv_size_left -= sizeof(cmd_tlv_t); ++ ++ if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, ++ MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) { ++ AP6211_ERR("SSID is not presented or corrupted ret=%d\n", nssid); ++ goto exit_proc; ++ } else { ++ if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) { ++ AP6211_ERR("%s scan duration corrupted field size %d\n", ++ __FUNCTION__, tlv_size_left); ++ goto exit_proc; ++ } ++ str_ptr++; ++ pno_time = simple_strtoul(str_ptr, &str_ptr, 16); ++ AP6211_DEBUG("%s: pno_time=%d\n", __FUNCTION__, pno_time); ++ ++ if (str_ptr[0] != 0) { ++ if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) { ++ AP6211_ERR("%s pno repeat : corrupted field\n", ++ __FUNCTION__); ++ goto exit_proc; ++ } ++ str_ptr++; ++ pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16); ++ AP6211_DEBUG("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat); ++ if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) { ++ AP6211_ERR("%s FREQ_EXPO_MAX corrupted field size\n", ++ __FUNCTION__); ++ goto exit_proc; ++ } ++ str_ptr++; ++ pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16); ++ AP6211_DEBUG("%s: pno_freq_expo_max=%d\n", ++ __FUNCTION__, pno_freq_expo_max); ++ } ++ } ++ } else { ++ AP6211_ERR("%s get wrong TLV command\n", __FUNCTION__); ++ goto exit_proc; ++ } ++ ++ res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max); ++ ++exit_proc: ++ return res; ++} ++#endif /* PNO_SUPPORT && !WL_SCHED_SCAN */ ++ ++static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len) ++{ ++ int ret; ++ int bytes_written = 0; ++ ++ ret = wl_cfg80211_get_p2p_dev_addr(ndev, (struct ether_addr*)command); ++ if (ret) ++ return 0; ++ bytes_written = sizeof(struct ether_addr); ++ return bytes_written; ++} ++ ++/** ++ * Global function definitions (declared in wl_android.h) ++ */ ++ ++int wl_android_wifi_on(struct net_device *dev) ++{ ++ int ret = 0; ++ int retry = POWERUP_MAX_RETRY; ++ ++ AP6211_DEBUG("%s in\n", __FUNCTION__); ++ if (!dev) { ++ AP6211_ERR("%s: dev is null\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ dhd_net_if_lock(dev); ++ if (!g_wifi_on) { ++ do { ++ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON); ++ ret = sdioh_start(NULL, 0); ++ if (ret == 0) ++ break; ++ AP6211_ERR("failed to power up wifi chip, retry again (%d left) **\n\n", ++ retry+1); ++ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); ++ } while (retry-- >= 0); ++ if (ret != 0) { ++ AP6211_ERR("failed to power up wifi chip, max retry reached **\n\n"); ++ goto exit; ++ } ++ ret = dhd_dev_reset(dev, FALSE); ++ if (ret) ++ goto err; ++ sdioh_start(NULL, 1); ++ if (!ret) { ++ if (dhd_dev_init_ioctl(dev) < 0) { ++ ret = -EFAULT; ++ goto err; ++ } ++ } ++#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB) ++ dhd_wlfc_init(bcmsdh_get_drvdata()); ++#endif ++ g_wifi_on = TRUE; ++ } ++ ++exit: ++ dhd_net_if_unlock(dev); ++ AP6211_DEBUG("%s: Success\n", __FUNCTION__); ++ return ret; ++err: ++ dhd_dev_reset(dev, TRUE); ++ sdioh_stop(NULL); ++ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); ++ dhd_net_if_unlock(dev); ++ AP6211_DEBUG("%s: Failed\n", __FUNCTION__); ++ ++ return ret; ++} ++ ++int wl_android_wifi_off(struct net_device *dev) ++{ ++ int ret = 0; ++ ++ AP6211_DEBUG("%s in\n", __FUNCTION__); ++ if (!dev) { ++ AP6211_DEBUG("%s: dev is null\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ dhd_net_if_lock(dev); ++ if (g_wifi_on) { ++#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB) ++ dhd_wlfc_deinit(bcmsdh_get_drvdata()); ++#endif ++ ret = dhd_dev_reset(dev, TRUE); ++ sdioh_stop(NULL); ++ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); ++ g_wifi_on = FALSE; ++ } ++ dhd_net_if_unlock(dev); ++ ++ return ret; ++} ++ ++static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len) ++{ ++ if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN) ++ return -1; ++ bcm_strncpy_s(fw_path, sizeof(fw_path), ++ command + strlen(CMD_SETFWPATH) + 1, MOD_PARAM_PATHLEN - 1); ++ if (strstr(fw_path, "apsta") != NULL) { ++ AP6211_DEBUG("GOT APSTA FIRMWARE\n"); ++ ap_fw_loaded = TRUE; ++ } else { ++ AP6211_DEBUG("GOT STA FIRMWARE\n"); ++ ap_fw_loaded = FALSE; ++ } ++ return 0; ++} ++ ++static int ++wl_android_set_pmk(struct net_device *dev, char *command, int total_len) ++{ ++ uchar pmk[33]; ++ int error = 0; ++ char smbuf[WLC_IOCTL_SMLEN]; ++#ifdef OKC_DEBUG ++ int i = 0; ++#endif ++ ++ bzero(pmk, sizeof(pmk)); ++ memcpy((char *)pmk, command + strlen("SET_PMK "), 32); ++ error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL); ++ if (error) { ++ AP6211_ERR("Failed to set PMK for OKC, error = %d\n", error); ++ } ++#ifdef OKC_DEBUG ++ AP6211_ERR("PMK is "); ++ for (i = 0; i < 32; i++) ++ AP6211_ERR("%02X ", pmk[i]); ++ ++ AP6211_ERR("\n"); ++#endif ++ return error; ++} ++ ++static int ++wl_android_okc_enable(struct net_device *dev, char *command, int total_len) ++{ ++ int error = 0; ++ char okc_enable = 0; ++ ++ okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0'; ++ error = wldev_iovar_setint(dev, "okc_enable", okc_enable); ++ if (error) { ++ AP6211_ERR("Failed to %s OKC, error = %d\n", ++ okc_enable ? "enable" : "disable", error); ++ } ++ ++ return error; ++} ++ ++int wl_android_set_roam_mode(struct net_device *dev, char *command, int total_len) ++{ ++ int error = 0; ++ int mode = 0; ++ ++ if (sscanf(command, "%*s %d", &mode) != 1) { ++ AP6211_ERR("%s: Failed to get Parameter\n", __FUNCTION__); ++ return -1; ++ } ++ ++ error = wldev_iovar_setint(dev, "roam_off", mode); ++ if (error) { ++ AP6211_ERR("%s: Failed to set roaming Mode %d, error = %d\n", ++ __FUNCTION__, mode, error); ++ return -1; ++ } ++ else ++ AP6211_ERR("%s: succeeded to set roaming Mode %d, error = %d\n", ++ __FUNCTION__, mode, error); ++ return 0; ++} ++ ++int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) ++{ ++#define PRIVATE_COMMAND_MAX_LEN 8192 ++ int ret = 0; ++ char *command = NULL; ++ int bytes_written = 0; ++ android_wifi_priv_cmd priv_cmd; ++ ++ net_os_wake_lock(net); ++ ++ if (!ifr->ifr_data) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) { ++ ret = -EFAULT; ++ goto exit; ++ } ++ if (priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) ++ { ++ AP6211_ERR("%s: too long priavte command\n", __FUNCTION__); ++ ret = -EINVAL; ++ } ++ command = kmalloc(priv_cmd.total_len, GFP_KERNEL); ++ if (!command) ++ { ++ AP6211_ERR("%s: failed to allocate memory\n", __FUNCTION__); ++ ret = -ENOMEM; ++ goto exit; ++ } ++ if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) { ++ ret = -EFAULT; ++ goto exit; ++ } ++ ++ AP6211_DEBUG("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name); ++ ++ if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) { ++ AP6211_DEBUG("%s, Received regular START command\n", __FUNCTION__); ++ bytes_written = wl_android_wifi_on(net); ++ } ++ else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) { ++ bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len); ++ } ++ ++ if (!g_wifi_on) { ++ AP6211_ERR("%s: Ignore private cmd \"%s\" - iface %s is down\n", ++ __FUNCTION__, command, ifr->ifr_name); ++ ret = 0; ++ goto exit; ++ } ++ ++ if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) { ++ bytes_written = wl_android_wifi_off(net); ++ } ++ else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) { ++ /* TBD: SCAN-ACTIVE */ ++ } ++ else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) { ++ /* TBD: SCAN-PASSIVE */ ++ } ++ else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) { ++ bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len); ++ } ++ else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) { ++ bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len); ++ } ++#ifdef PKT_FILTER_SUPPORT ++ else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) { ++ bytes_written = net_os_enable_packet_filter(net, 1); ++ } ++ else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) { ++ bytes_written = net_os_enable_packet_filter(net, 0); ++ } ++ else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) { ++ int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0'; ++ bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num); ++ } ++ else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) { ++ int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0'; ++ bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num); ++ } ++#endif /* PKT_FILTER_SUPPORT */ ++ else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) { ++ /* TBD: BTCOEXSCAN-START */ ++ } ++ else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) { ++ /* TBD: BTCOEXSCAN-STOP */ ++ } ++ else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) { ++#ifdef WL_CFG80211 ++ bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command); ++#else ++#ifdef PKT_FILTER_SUPPORT ++ uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0'; ++ ++ if (mode == 1) ++ net_os_enable_packet_filter(net, 0); /* DHCP starts */ ++ else ++ net_os_enable_packet_filter(net, 1); /* DHCP ends */ ++#endif /* PKT_FILTER_SUPPORT */ ++#endif /* WL_CFG80211 */ ++ } ++ else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) { ++ bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len); ++ } ++ else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) { ++ bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len); ++ } ++ else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) { ++ uint band = *(command + strlen(CMD_SETBAND) + 1) - '0'; ++#ifdef WL_HOST_BAND_MGMT ++ if (wl_cfg80211_set_band(net, band) < 0) { ++ bytes_written = -1; ++ goto exit; ++ } ++ if (band == WLC_BAND_AUTO) ++ bytes_written = wldev_set_band(net, band); ++#else ++ bytes_written = wldev_set_band(net, band); ++#endif /* WL_HOST_BAND_MGMT */ ++ } ++ else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) { ++ bytes_written = wl_android_get_band(net, command, priv_cmd.total_len); ++ } ++#ifdef WL_CFG80211 ++ /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */ ++ else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) { ++ char *country_code = command + strlen(CMD_COUNTRY) + 1; ++ bytes_written = wldev_set_country(net, country_code); ++ } ++#endif /* WL_CFG80211 */ ++#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN) ++ else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) { ++ bytes_written = dhd_dev_pno_reset(net); ++ } ++ else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) { ++ bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len); ++ } ++ else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) { ++ uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0'; ++ bytes_written = dhd_dev_pno_enable(net, pfn_enabled); ++ } ++#endif /* PNO_SUPPORT && !WL_SCHED_SCAN */ ++ else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) { ++ bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len); ++ } ++ else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) { ++ int skip = strlen(CMD_P2P_SET_NOA) + 1; ++ bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, ++ priv_cmd.total_len - skip); ++ } ++#if !defined WL_ENABLE_P2P_IF ++ else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) { ++ bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len); ++ } ++#endif /* WL_ENABLE_P2P_IF */ ++ else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) { ++ int skip = strlen(CMD_P2P_SET_PS) + 1; ++ bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, ++ priv_cmd.total_len - skip); ++ } ++#ifdef WL_CFG80211 ++ else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE, ++ strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) { ++ int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3; ++ bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip, ++ priv_cmd.total_len - skip, *(command + skip - 2) - '0'); ++ } ++#endif /* WL_CFG80211 */ ++ else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) ++ bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len); ++ else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) ++ bytes_written = wl_android_okc_enable(net, command, priv_cmd.total_len); ++ else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0) ++ bytes_written = wl_android_set_roam_mode(net, command, priv_cmd.total_len); ++ else { ++ AP6211_ERR("Unknown PRIVATE command %s - ignored\n", command); ++ snprintf(command, 3, "OK"); ++ bytes_written = strlen("OK"); ++ } ++ ++ if (bytes_written >= 0) { ++ if ((bytes_written == 0) && (priv_cmd.total_len > 0)) ++ command[0] = '\0'; ++ if (bytes_written >= priv_cmd.total_len) { ++ AP6211_ERR("%s: bytes_written = %d\n", __FUNCTION__, bytes_written); ++ bytes_written = priv_cmd.total_len; ++ } else { ++ bytes_written++; ++ } ++ priv_cmd.used_len = bytes_written; ++ if (copy_to_user(priv_cmd.buf, command, bytes_written)) { ++ AP6211_ERR("%s: failed to copy data to user buffer\n", __FUNCTION__); ++ ret = -EFAULT; ++ } ++ } ++ else { ++ ret = bytes_written; ++ } ++ ++exit: ++ net_os_wake_unlock(net); ++ if (command) { ++ kfree(command); ++ } ++ ++ return ret; ++} ++ ++int wl_android_init(void) ++{ ++ int ret = 0; ++ ++ dhd_msg_level |= DHD_ERROR_VAL; ++#ifdef ENABLE_INSMOD_NO_FW_LOAD ++ dhd_download_fw_on_driverload = FALSE; ++#endif /* ENABLE_INSMOD_NO_FW_LOAD */ ++ if (!iface_name[0]) { ++ memset(iface_name, 0, IFNAMSIZ); ++ bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ); ++ } ++ return ret; ++} ++ ++int wl_android_exit(void) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++void wl_android_post_init(void) ++{ ++ if (!dhd_download_fw_on_driverload) { ++ /* Call customer gpio to turn off power with WL_REG_ON signal */ ++ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); ++ g_wifi_on = 0; ++ } ++} ++ ++#if defined(RSSIAVG) ++void ++wl_free_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl) ++{ ++ wl_rssi_cache_t *node, *cur, **rssi_head; ++ int i=0; ++ ++ rssi_head = &rssi_cache_ctrl->m_cache_head; ++ node = *rssi_head; ++ ++ for (;node;) { ++ AP6211_DEBUG("%s: Free %d with BSSID %pM\n", ++ __FUNCTION__, i, &node->BSSID); ++ cur = node; ++ node = cur->next; ++ kfree(cur); ++ i++; ++ } ++ *rssi_head = NULL; ++} ++ ++void ++wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl) ++{ ++ wl_rssi_cache_t *node, *prev, **rssi_head; ++ int i = -1, tmp = 0; ++#if defined(BSSCACHE) ++ int max = BSSCACHE_LEN; ++#else ++ int max = RSSICACHE_LEN; ++#endif ++ ++ rssi_head = &rssi_cache_ctrl->m_cache_head; ++ node = *rssi_head; ++ prev = node; ++ for (;node;) { ++ i++; ++ if (node->dirty >= max || node->dirty >= RSSICACHE_LEN) { ++ if (node == *rssi_head) { ++ tmp = 1; ++ *rssi_head = node->next; ++ } else { ++ tmp = 0; ++ prev->next = node->next; ++ } ++ AP6211_DEBUG("%s: Del %d with BSSID %pM\n", ++ __FUNCTION__, i, &node->BSSID); ++ kfree(node); ++ if (tmp == 1) { ++ node = *rssi_head; ++ prev = node; ++ } else { ++ node = prev->next; ++ } ++ continue; ++ } ++ prev = node; ++ node = node->next; ++ } ++} ++ ++void ++wl_reset_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl) ++{ ++ wl_rssi_cache_t *node, **rssi_head; ++ ++ rssi_head = &rssi_cache_ctrl->m_cache_head; ++ ++ /* reset dirty */ ++ node = *rssi_head; ++ for (;node;) { ++ node->dirty += 1; ++ node = node->next; ++ } ++} ++ ++void ++wl_update_connected_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, struct net_device *net) ++{ ++ wl_rssi_cache_t *node, *prev, **rssi_head; ++ int j, k=0; ++ int rssi, error; ++ struct ether_addr bssid; ++ ++ error = wldev_ioctl(net, WLC_GET_BSSID, &bssid, sizeof(bssid), false); ++ if (error) ++ return; ++ error = wldev_get_rssi(net, &rssi); ++ if (error) ++ return; ++ ++ /* update RSSI */ ++ rssi_head = &rssi_cache_ctrl->m_cache_head; ++ node = *rssi_head; ++ for (;node;) { ++ if (!memcmp(&node->BSSID, &bssid, ETHER_ADDR_LEN)) { ++ AP6211_DEBUG("%s: Update %d with BSSID %pM, RSSI=%d\n", ++ __FUNCTION__, k, &bssid, rssi); ++ for(j=0; jRSSI[j] = node->RSSI[j+1]; ++ node->RSSI[j] = rssi; ++ node->dirty = 0; ++ break; ++ } ++ prev = node; ++ node = node->next; ++ k++; ++ } ++} ++ ++void ++wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, wl_scan_results_t *ss_list) ++{ ++ wl_rssi_cache_t *node, *prev, *leaf, **rssi_head; ++ wl_bss_info_t *bi = NULL; ++ int i, j, k; ++ ++ if (!ss_list->count) ++ return; ++ ++ rssi_head = &rssi_cache_ctrl->m_cache_head; ++ ++ /* update RSSI */ ++ for (i = 0; i < ss_list->count; i++) { ++ node = *rssi_head; ++ prev = NULL; ++ k = 0; ++ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; ++ for (;node;) { ++ if (!memcmp(&node->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) { ++ AP6211_DEBUG("%s: Update %d with BSSID %pM, RSSI=%d, SSID \"%s\"\n", ++ __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID); ++ for(j=0; jRSSI[j] = node->RSSI[j+1]; ++ node->RSSI[j] = dtoh16(bi->RSSI); ++ node->dirty = 0; ++ break; ++ } ++ prev = node; ++ node = node->next; ++ k++; ++ } ++ ++ if (node) ++ continue; ++ ++ leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL); ++ if (!leaf) { ++ AP6211_ERR("%s: Memory alloc failure %d\n", ++ __FUNCTION__, sizeof(wl_rssi_cache_t)); ++ return; ++ } ++ AP6211_DEBUG("%s: Add %d with cached BSSID %pM, RSSI=%d, SSID \"%s\" in the leaf\n", ++ __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID); ++ ++ leaf->next = NULL; ++ leaf->dirty = 0; ++ memcpy(&leaf->BSSID, &bi->BSSID, ETHER_ADDR_LEN); ++ for (j=0; jRSSI[j] = dtoh16(bi->RSSI); ++ ++ if (!prev) ++ *rssi_head = leaf; ++ else ++ prev->next = leaf; ++ } ++} ++ ++int16 ++wl_get_avg_rssi(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, void *addr) ++{ ++ wl_rssi_cache_t *node, **rssi_head; ++ int j, rssi_sum, rssi=-200; ++ ++ rssi_head = &rssi_cache_ctrl->m_cache_head; ++ ++ /* reset dirty */ ++ node = *rssi_head; ++ for (;node;) { ++ if (!memcmp(&node->BSSID, addr, ETHER_ADDR_LEN)) { ++ rssi_sum = 0; ++ rssi = 0; ++ for (j=0; jRSSI[RSSIAVG_LEN-j-1]; ++ rssi = rssi_sum / j; ++ break; ++ } ++ node = node->next; ++ } ++ if (rssi >= -2) ++ rssi = -2; ++ if (rssi == -200) { ++ AP6211_ERR("%s: BSSID %pM does not in RSSI cache\n", ++ __FUNCTION__, addr); ++ } ++ return (int16)rssi; ++} ++#endif ++ ++#if defined(RSSIOFFSET) ++int ++wl_update_rssi_offset(int rssi) ++{ ++ uint chip, chiprev; ++ ++ chip = dhd_bus_chip_id(bcmsdh_get_drvdata()); ++ chiprev = dhd_bus_chiprev_id(bcmsdh_get_drvdata()); ++ if (chip == BCM4330_CHIP_ID && chiprev == BCM4330B2_CHIP_REV) { ++#if defined(RSSIOFFSET_NEW) ++ int j; ++ for (j=0; j= -2) ++ rssi = -2; ++ return rssi; ++} ++#endif ++ ++#if defined(BSSCACHE) ++#define WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN 32 ++ ++void ++wl_free_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl) ++{ ++ wl_bss_cache_t *node, *cur, **bss_head; ++ int i=0; ++ ++ AP6211_DEBUG("%s called\n", __FUNCTION__); ++ ++ bss_head = &bss_cache_ctrl->m_cache_head; ++ node = *bss_head; ++ ++ for (;node;) { ++ AP6211_DEBUG("%s: Free %d with BSSID %pM\n", ++ __FUNCTION__, i, &node->results.bss_info->BSSID); ++ cur = node; ++ node = cur->next; ++ kfree(cur); ++ i++; ++ } ++ *bss_head = NULL; ++} ++ ++void ++wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl) ++{ ++ wl_bss_cache_t *node, *prev, **bss_head; ++ int i = -1, tmp = 0; ++ ++ bss_head = &bss_cache_ctrl->m_cache_head; ++ node = *bss_head; ++ prev = node; ++ for (;node;) { ++ i++; ++ if (node->dirty >= BSSCACHE_LEN) { ++ if (node == *bss_head) { ++ tmp = 1; ++ *bss_head = node->next; ++ } else { ++ tmp = 0; ++ prev->next = node->next; ++ } ++ AP6211_DEBUG("%s: Del %d with BSSID %pM, RSSI=%d, SSID \"%s\"\n", ++ __FUNCTION__, i, &node->results.bss_info->BSSID, ++ dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID); ++ kfree(node); ++ if (tmp == 1) { ++ node = *bss_head; ++ prev = node; ++ } else { ++ node = prev->next; ++ } ++ continue; ++ } ++ prev = node; ++ node = node->next; ++ } ++} ++ ++void ++wl_reset_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl) ++{ ++ wl_bss_cache_t *node, **bss_head; ++ ++ bss_head = &bss_cache_ctrl->m_cache_head; ++ ++ /* reset dirty */ ++ node = *bss_head; ++ for (;node;) { ++ node->dirty += 1; ++ node = node->next; ++ } ++} ++ ++void ++wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, wl_scan_results_t *ss_list) ++{ ++ wl_bss_cache_t *node, *prev, *leaf, *tmp, **bss_head; ++ wl_bss_info_t *bi = NULL; ++ int i, k=0; ++ ++ if (!ss_list->count) ++ return; ++ ++ bss_head = &bss_cache_ctrl->m_cache_head; ++ ++ for (i=0; i < ss_list->count; i++) { ++ node = *bss_head; ++ prev = NULL; ++ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info; ++ ++ for (;node;) { ++ if (!memcmp(&node->results.bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) { ++ tmp = node; ++ leaf = kmalloc(dtoh32(bi->length) + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL); ++ if (!leaf) { ++ AP6211_ERR("%s: Memory alloc failure %d and keep old BSS info\n", ++ __FUNCTION__, dtoh32(bi->length) + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN); ++ break; ++ } ++ ++ memcpy(leaf->results.bss_info, bi, dtoh32(bi->length)); ++ leaf->next = node->next; ++ leaf->dirty = 0; ++ leaf->results.count = 1; ++ leaf->results.version = ss_list->version; ++ AP6211_DEBUG("%s: Update %d with BSSID %pM, RSSI=%d, SSID \"%s\"\n", ++ __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID); ++ if (!prev) ++ *bss_head = leaf; ++ else ++ prev->next = leaf; ++ node = leaf; ++ prev = node; ++ ++ kfree(tmp); ++ k++; ++ break; ++ } ++ prev = node; ++ node = node->next; ++ } ++ ++ if (node) ++ continue; ++ ++ leaf = kmalloc(dtoh32(bi->length) + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL); ++ if (!leaf) { ++ AP6211_ERR("%s: Memory alloc failure %d\n", __FUNCTION__, ++ dtoh32(bi->length) + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN); ++ return; ++ } ++ AP6211_DEBUG("%s: Add %d with cached BSSID %pM, RSSI=%d, SSID \"%s\" in the leaf\n", ++ __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID); ++ ++ memcpy(leaf->results.bss_info, bi, dtoh32(bi->length)); ++ leaf->next = NULL; ++ leaf->dirty = 0; ++ leaf->results.count = 1; ++ leaf->results.version = ss_list->version; ++ k++; ++ ++ if (!prev) ++ *bss_head = leaf; ++ else ++ prev->next = leaf; ++ } ++} ++ ++void ++wl_run_bss_cache_timer(wl_bss_cache_ctrl_t *bss_cache_ctrl, int kick_off) ++{ ++ struct timer_list **timer; ++ ++ timer = &bss_cache_ctrl->m_timer; ++ ++ if (*timer) { ++ if (kick_off) { ++ (*timer)->expires = jiffies + BSSCACHE_TIME * HZ / 1000; ++ add_timer(*timer); ++ AP6211_DEBUG("%s: timer starts\n", __FUNCTION__); ++ } else { ++ del_timer_sync(*timer); ++ AP6211_DEBUG("%s: timer stops\n", __FUNCTION__); ++ } ++ } ++} ++ ++void ++wl_set_bss_cache_timer_flag(ulong data) ++{ ++ wl_bss_cache_ctrl_t *bss_cache_ctrl = (wl_bss_cache_ctrl_t *)data; ++ ++ bss_cache_ctrl->m_timer_expired = 1; ++ AP6211_DEBUG("%s called\n", __FUNCTION__); ++} ++ ++void ++wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl) ++{ ++ AP6211_DEBUG("%s:\n", __FUNCTION__); ++ wl_free_bss_cache(bss_cache_ctrl); ++ wl_run_bss_cache_timer(bss_cache_ctrl, 0); ++ if (bss_cache_ctrl->m_timer) { ++ kfree(bss_cache_ctrl->m_timer); ++ } ++} ++ ++void ++wl_init_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl) ++{ ++ AP6211_DEBUG("%s:\n", __FUNCTION__); ++ bss_cache_ctrl->m_timer_expired = 0; ++ ++ bss_cache_ctrl->m_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL); ++ if (!bss_cache_ctrl->m_timer) { ++ AP6211_ERR("%s: Memory alloc failure\n", __FUNCTION__ ); ++ return; ++ } ++ init_timer(bss_cache_ctrl->m_timer); ++ bss_cache_ctrl->m_timer->function = (void *)wl_set_bss_cache_timer_flag; ++ bss_cache_ctrl->m_timer->data = (ulong)bss_cache_ctrl; ++} ++#endif ++ ++/** ++ * Functions for Android WiFi card detection ++ */ ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++ ++static int g_wifidev_registered = 0; ++static struct semaphore wifi_control_sem; ++static struct wifi_platform_data *wifi_control_data = NULL; ++static struct resource *wifi_irqres = NULL; ++ ++static int wifi_add_dev(void); ++static void wifi_del_dev(void); ++ ++int wl_android_wifictrl_func_add(void) ++{ ++ int ret = 0; ++ sema_init(&wifi_control_sem, 0); ++ ++ ret = wifi_add_dev(); ++ if (ret) { ++ AP6211_ERR("%s: platform_driver_register failed\n", __FUNCTION__); ++ return ret; ++ } ++ g_wifidev_registered = 1; ++ ++ /* Waiting callback after platform_driver_register is done or exit with error */ ++ if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) { ++ ret = -EINVAL; ++ AP6211_ERR("%s: platform_driver_register timeout\n", __FUNCTION__); ++ } ++ ++ return ret; ++} ++ ++void wl_android_wifictrl_func_del(void) ++{ ++ if (g_wifidev_registered) ++ { ++ wifi_del_dev(); ++ g_wifidev_registered = 0; ++ } ++} ++ ++void* wl_android_prealloc(int section, unsigned long size) ++{ ++ void *alloc_ptr = NULL; ++ if (wifi_control_data && wifi_control_data->mem_prealloc) { ++ alloc_ptr = wifi_control_data->mem_prealloc(section, size); ++ if (alloc_ptr) { ++ AP6211_DEBUG("success alloc section %d\n", section); ++ if (size != 0L) ++ bzero(alloc_ptr, size); ++ return alloc_ptr; ++ } ++ } ++ ++ AP6211_ERR("can't alloc section %d\n", section); ++ return NULL; ++} ++ ++int wifi_get_irq_number(unsigned long *irq_flags_ptr) ++{ ++ if (wifi_irqres) { ++ *irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK; ++ return (int)wifi_irqres->start; ++ } ++#ifdef CUSTOM_OOB_GPIO_NUM ++ return CUSTOM_OOB_GPIO_NUM; ++#else ++ return -1; ++#endif ++} ++ ++int wifi_set_power(int on, unsigned long msec) ++{ ++ AP6211_ERR("%s = %d\n", __FUNCTION__, on); ++ if (wifi_control_data && wifi_control_data->set_power) { ++ wifi_control_data->set_power(on); ++ } ++ if (msec) ++ msleep(msec); ++ return 0; ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) ++int wifi_get_mac_addr(unsigned char *buf) ++{ ++ AP6211_ERR("%s\n", __FUNCTION__); ++ if (!buf) ++ return -EINVAL; ++ if (wifi_control_data && wifi_control_data->get_mac_addr) { ++ return wifi_control_data->get_mac_addr(buf); ++ } ++ return -EOPNOTSUPP; ++} ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++void *wifi_get_country_code(char *ccode) ++{ ++ AP6211_DEBUG("%s\n", __FUNCTION__); ++ if (!ccode) ++ return NULL; ++ if (wifi_control_data && wifi_control_data->get_country_code) { ++ return wifi_control_data->get_country_code(ccode); ++ } ++ return NULL; ++} ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ ++ ++static int wifi_set_carddetect(int on) ++{ ++ AP6211_ERR("%s = %d\n", __FUNCTION__, on); ++ if (wifi_control_data && wifi_control_data->set_carddetect) { ++ wifi_control_data->set_carddetect(on); ++ } ++ return 0; ++} ++ ++static int wifi_probe(struct platform_device *pdev) ++{ ++ struct wifi_platform_data *wifi_ctrl = ++ (struct wifi_platform_data *)(pdev->dev.platform_data); ++ ++ wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq"); ++ if (wifi_irqres == NULL) ++ wifi_irqres = platform_get_resource_byname(pdev, ++ IORESOURCE_IRQ, "bcm4329_wlan_irq"); ++ wifi_control_data = wifi_ctrl; ++ wifi_set_power(1, 0); /* Power On */ ++ wifi_set_carddetect(1); /* CardDetect (0->1) */ ++ ++ up(&wifi_control_sem); ++ return 0; ++} ++ ++static int wifi_remove(struct platform_device *pdev) ++{ ++ struct wifi_platform_data *wifi_ctrl = ++ (struct wifi_platform_data *)(pdev->dev.platform_data); ++ ++ AP6211_ERR("## %s\n", __FUNCTION__); ++ wifi_control_data = wifi_ctrl; ++ ++ wifi_set_power(0, WIFI_TURNOFF_DELAY); /* Power Off */ ++ wifi_set_carddetect(0); /* CardDetect (1->0) */ ++ ++ up(&wifi_control_sem); ++ return 0; ++} ++ ++static int wifi_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ AP6211_DEBUG("##> %s\n", __FUNCTION__); ++#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) ++ if (dhd_os_check_wakelock(bcmsdh_get_drvdata())) ++ return -EBUSY; ++#endif /* defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI) */ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && 1 ++ bcmsdh_oob_intr_set(0); ++#endif /* (OOB_INTR_ONLY) */ ++ return 0; ++} ++ ++static int wifi_resume(struct platform_device *pdev) ++{ ++ AP6211_DEBUG("##> %s\n", __FUNCTION__); ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && 1 ++ if (dhd_os_check_if_up(bcmsdh_get_drvdata())) ++ bcmsdh_oob_intr_set(1); ++#endif /* (OOB_INTR_ONLY) */ ++ return 0; ++} ++ ++static struct platform_driver wifi_device = { ++ .probe = wifi_probe, ++ .remove = wifi_remove, ++ .suspend = wifi_suspend, ++ .resume = wifi_resume, ++ .driver = { ++ .name = "bcmdhd_wlan", ++ } ++}; ++ ++static struct platform_driver wifi_device_legacy = { ++ .probe = wifi_probe, ++ .remove = wifi_remove, ++ .suspend = wifi_suspend, ++ .resume = wifi_resume, ++ .driver = { ++ .name = "bcm4329_wlan", ++ } ++}; ++ ++static int wifi_add_dev(void) ++{ ++ int ret = 0; ++ AP6211_DEBUG("## Calling platform_driver_register\n"); ++ ret = platform_driver_register(&wifi_device); ++ if (ret) ++ return ret; ++ ++ ret = platform_driver_register(&wifi_device_legacy); ++ return ret; ++} ++ ++static void wifi_del_dev(void) ++{ ++ AP6211_DEBUG("## Unregister platform_driver_register\n"); ++ platform_driver_unregister(&wifi_device); ++ platform_driver_unregister(&wifi_device_legacy); ++} ++#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ +diff --git a/drivers/net/wireless/ap6211/wl_android.h b/drivers/net/wireless/ap6211/wl_android.h +new file mode 100755 +index 0000000..d933e06 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_android.h +@@ -0,0 +1,124 @@ ++/* ++ * Linux cfg80211 driver - Android related functions ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_android.h 367273 2012-11-07 09:58:55Z $ ++ */ ++ ++#include ++#include ++#include ++ ++/* If any feature uses the Generic Netlink Interface, put it here to enable WL_GENL ++ * automatically ++ */ ++ ++/** ++ * Android platform dependent functions, feel free to add Android specific functions here ++ * (save the macros in dhd). Please do NOT declare functions that are NOT exposed to dhd ++ * or cfg, define them as static in wl_android.c ++ */ ++ ++/** ++ * wl_android_init will be called from module init function (dhd_module_init now), similarly ++ * wl_android_exit will be called from module exit function (dhd_module_cleanup now) ++ */ ++int wl_android_init(void); ++int wl_android_exit(void); ++void wl_android_post_init(void); ++int wl_android_wifi_on(struct net_device *dev); ++int wl_android_wifi_off(struct net_device *dev); ++int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd); ++ ++#define BSSCACHE ++#define RSSIAVG ++#define RSSIOFFSET ++//#define RSSIOFFSET_NEW ++ ++#if defined(RSSIAVG) ++#define RSSIAVG_LEN 8 ++#define RSSICACHE_LEN 8 ++ ++typedef struct wl_rssi_cache { ++ struct wl_rssi_cache *next; ++ int dirty; ++ struct ether_addr BSSID; ++ int16 RSSI[RSSIAVG_LEN]; ++} wl_rssi_cache_t; ++ ++typedef struct wl_rssi_cache_ctrl { ++ wl_rssi_cache_t *m_cache_head; ++} wl_rssi_cache_ctrl_t; ++ ++void wl_free_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl); ++void wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl); ++void wl_reset_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl); ++void wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, wl_scan_results_t *ss_list); ++void wl_update_connected_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, struct net_device *net); ++int16 wl_get_avg_rssi(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, void *addr); ++#endif ++ ++#if defined(RSSIOFFSET) ++#define RSSI_OFFSET 5 ++#define RSSI_MAX -80 ++#define RSSI_MIN -94 ++#define RSSI_INT ((RSSI_MAX-RSSI_MIN)/RSSI_OFFSET) ++#define BCM4330_CHIP_ID 0x4330 ++#define BCM4330B2_CHIP_REV 4 ++int wl_update_rssi_offset(int rssi); ++#endif ++ ++#if defined(BSSCACHE) ++#define BSSCACHE_LEN 8 ++#define BSSCACHE_TIME 15000 ++ ++typedef struct wl_bss_cache { ++ struct wl_bss_cache *next; ++ int dirty; ++ wl_scan_results_t results; ++} wl_bss_cache_t; ++ ++typedef struct wl_bss_cache_ctrl { ++ wl_bss_cache_t *m_cache_head; ++ struct timer_list *m_timer; ++ int m_timer_expired; ++} wl_bss_cache_ctrl_t; ++ ++void wl_free_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl); ++void wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl); ++void wl_reset_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl); ++void wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, wl_scan_results_t *ss_list); ++void wl_run_bss_cache_timer(wl_bss_cache_ctrl_t *bss_cache_ctrl, int kick_off); ++void wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl); ++void wl_init_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl); ++#endif ++ ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++int wl_android_wifictrl_func_add(void); ++void wl_android_wifictrl_func_del(void); ++void* wl_android_prealloc(int section, unsigned long size); ++ ++int wifi_get_irq_number(unsigned long *irq_flags_ptr); ++int wifi_set_power(int on, unsigned long msec); ++int wifi_get_mac_addr(unsigned char *buf); ++void *wifi_get_country_code(char *ccode); ++#endif /* CONFIG_WIFI_CONTROL_FUNC */ +diff --git a/drivers/net/wireless/ap6211/wl_cfg80211.c b/drivers/net/wireless/ap6211/wl_cfg80211.c +new file mode 100755 +index 0000000..1ebce14 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_cfg80211.c +@@ -0,0 +1,10129 @@ ++/* ++ * Linux cfg80211 driver ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_cfg80211.c 374275 2012-12-12 11:44:18Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#ifdef PROP_TXSTATUS ++#include ++#endif ++#ifdef BCMWAPI_WPI ++/* these items should evetually go into wireless.h of the linux system headfile dir */ ++#ifndef IW_ENCODE_ALG_SM4 ++#define IW_ENCODE_ALG_SM4 0x20 ++#endif ++ ++#ifndef IW_AUTH_WAPI_ENABLED ++#define IW_AUTH_WAPI_ENABLED 0x20 ++#endif ++ ++#ifndef IW_AUTH_WAPI_VERSION_1 ++#define IW_AUTH_WAPI_VERSION_1 0x00000008 ++#endif ++ ++#ifndef IW_AUTH_CIPHER_SMS4 ++#define IW_AUTH_CIPHER_SMS4 0x00000020 ++#endif ++ ++#ifndef IW_AUTH_KEY_MGMT_WAPI_PSK ++#define IW_AUTH_KEY_MGMT_WAPI_PSK 4 ++#endif ++ ++#ifndef IW_AUTH_KEY_MGMT_WAPI_CERT ++#define IW_AUTH_KEY_MGMT_WAPI_CERT 8 ++#endif ++#endif /* BCMWAPI_WPI */ ++ ++#ifdef BCMWAPI_WPI ++#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED)) ++#else /* BCMWAPI_WPI */ ++#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) ++#endif /* BCMWAPI_WPI */ ++#ifdef WL11U ++#ifndef WL_ENABLE_P2P_IF ++#error "You should enable WL_ENABLE_P2P_IF and Only supported in JB" ++#endif ++#endif /* WL11U */ ++ ++#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) ++ ++static struct device *cfg80211_parent_dev = NULL; ++struct wl_priv *wlcfg_drv_priv = NULL; ++u32 wl_dbg_level = WL_DBG_ERR; ++ ++#define MAX_WAIT_TIME 1500 ++ ++#ifdef VSDB ++/* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */ ++#define DEFAULT_SLEEP_TIME_VSDB 200 ++#define OFF_CHAN_TIME_THRESHOLD_MS 200 ++ ++/* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */ ++#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl) \ ++ do { \ ++ if (wl_get_drv_status(wl, CONNECTED, wl_to_prmry_ndev(wl)) || \ ++ wl_get_drv_status(wl, CONNECTING, wl_to_prmry_ndev(wl))) { \ ++ msleep(DEFAULT_SLEEP_TIME_VSDB); \ ++ } \ ++ } while (0) ++#else /* VSDB */ ++/* if not VSDB, do nothing */ ++#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl) ++#endif /* VSDB */ ++ ++#ifdef WL_CFG80211_SYNC_GON ++#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(wl) \ ++ (wl_get_drv_status_all(wl, SENDING_ACT_FRM) || \ ++ wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) ++#else ++#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(wl) wl_get_drv_status_all(wl, SENDING_ACT_FRM) ++#endif /* WL_CFG80211_SYNC_GON */ ++ ++#define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL ++ ++ ++#define DNGL_FUNC(func, parameters) func parameters; ++#define COEX_DHCP ++ ++#define WLAN_EID_SSID 0 ++#define CH_MIN_5G_CHANNEL 34 ++#define CH_MIN_2G_CHANNEL 1 ++ ++/* This is to override regulatory domains defined in cfg80211 module (reg.c) ++ * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN ++ * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165). ++ * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels. ++ * All the chnages in world regulatory domain are to be done here. ++ */ ++static const struct ieee80211_regdomain brcm_regdom = { ++ .n_reg_rules = 4, ++ .alpha2 = "99", ++ .reg_rules = { ++ /* IEEE 802.11b/g, channels 1..11 */ ++ REG_RULE(2412-10, 2472+10, 40, 6, 20, 0), ++ /* If any */ ++ /* IEEE 802.11 channel 14 - Only JP enables ++ * this and for 802.11b only ++ */ ++ REG_RULE(2484-10, 2484+10, 20, 6, 20, 0), ++ /* IEEE 802.11a, channel 36..64 */ ++ REG_RULE(5150-10, 5350+10, 40, 6, 20, 0), ++ /* IEEE 802.11a, channel 100..165 */ ++ REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), } ++}; ++ ++ ++/* Data Element Definitions */ ++#define WPS_ID_CONFIG_METHODS 0x1008 ++#define WPS_ID_REQ_TYPE 0x103A ++#define WPS_ID_DEVICE_NAME 0x1011 ++#define WPS_ID_VERSION 0x104A ++#define WPS_ID_DEVICE_PWD_ID 0x1012 ++#define WPS_ID_REQ_DEV_TYPE 0x106A ++#define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053 ++#define WPS_ID_PRIM_DEV_TYPE 0x1054 ++ ++/* Device Password ID */ ++#define DEV_PW_DEFAULT 0x0000 ++#define DEV_PW_USER_SPECIFIED 0x0001, ++#define DEV_PW_MACHINE_SPECIFIED 0x0002 ++#define DEV_PW_REKEY 0x0003 ++#define DEV_PW_PUSHBUTTON 0x0004 ++#define DEV_PW_REGISTRAR_SPECIFIED 0x0005 ++ ++/* Config Methods */ ++#define WPS_CONFIG_USBA 0x0001 ++#define WPS_CONFIG_ETHERNET 0x0002 ++#define WPS_CONFIG_LABEL 0x0004 ++#define WPS_CONFIG_DISPLAY 0x0008 ++#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010 ++#define WPS_CONFIG_INT_NFC_TOKEN 0x0020 ++#define WPS_CONFIG_NFC_INTERFACE 0x0040 ++#define WPS_CONFIG_PUSHBUTTON 0x0080 ++#define WPS_CONFIG_KEYPAD 0x0100 ++#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280 ++#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480 ++#define WPS_CONFIG_VIRT_DISPLAY 0x2008 ++#define WPS_CONFIG_PHY_DISPLAY 0x4008 ++ ++#define PM_BLOCK 1 ++#define PM_ENABLE 0 ++/* ++ * cfg80211_ops api/callback list ++ */ ++static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, ++ const struct ether_addr *sa, const struct ether_addr *bssid, ++ u8 **pheader, u32 *body_len, u8 *pbody); ++static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_scan_request *request, ++ struct cfg80211_ssid *this_ssid); ++static s32 wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_scan_request *request); ++static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); ++static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_ibss_params *params); ++static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, ++ struct net_device *dev); ++static s32 wl_cfg80211_get_station(struct wiphy *wiphy, ++ struct net_device *dev, u8 *mac, ++ struct station_info *sinfo); ++static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, ++ struct net_device *dev, bool enabled, ++ s32 timeout); ++static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_connect_params *sme); ++static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, ++ u16 reason_code); ++static s32 wl_cfg80211_set_tx_power(struct wiphy *wiphy, ++ enum nl80211_tx_power_setting type, ++ s32 dbm); ++static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm); ++static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, ++ struct net_device *dev, ++ u8 key_idx, bool unicast, bool multicast); ++static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, bool pairwise, const u8 *mac_addr, ++ struct key_params *params); ++static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, bool pairwise, const u8 *mac_addr); ++static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, bool pairwise, const u8 *mac_addr, ++ void *cookie, void (*callback) (void *cookie, ++ struct key_params *params)); ++static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, ++ struct net_device *dev, u8 key_idx); ++static s32 wl_cfg80211_resume(struct wiphy *wiphy); ++#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ ++ 2, 0)) ++static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, ++ struct net_device *dev, u64 cookie); ++static s32 wl_cfg80211_del_station(struct wiphy *wiphy, ++ struct net_device *ndev, u8* mac_addr); ++#endif ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) ++static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow); ++#else ++static s32 wl_cfg80211_suspend(struct wiphy *wiphy); ++#endif ++static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_pmksa *pmksa); ++static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_pmksa *pmksa); ++static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, ++ struct net_device *dev); ++static s32 wl_notify_escan_complete(struct wl_priv *wl, ++ struct net_device *ndev, bool aborted, bool fw_abort); ++/* ++ * event & event Q handlers for cfg80211 interfaces ++ */ ++static s32 wl_create_event_handler(struct wl_priv *wl); ++static void wl_destroy_event_handler(struct wl_priv *wl); ++static s32 wl_event_handler(void *data); ++static void wl_init_eq(struct wl_priv *wl); ++static void wl_flush_eq(struct wl_priv *wl); ++static unsigned long wl_lock_eq(struct wl_priv *wl); ++static void wl_unlock_eq(struct wl_priv *wl, unsigned long flags); ++static void wl_init_eq_lock(struct wl_priv *wl); ++static void wl_init_event_handler(struct wl_priv *wl); ++static struct wl_event_q *wl_deq_event(struct wl_priv *wl); ++static s32 wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 type, ++ const wl_event_msg_t *msg, void *data); ++static void wl_put_event(struct wl_event_q *e); ++static void wl_wakeup_event(struct wl_priv *wl); ++static s32 wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++static s32 wl_notify_connect_status(struct wl_priv *wl, ++ struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++static s32 wl_notify_roaming_status(struct wl_priv *wl, ++ struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++static s32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++static s32 wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data, bool completed); ++static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++#ifdef WL_SCHED_SCAN ++static s32 ++wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++#endif /* WL_SCHED_SCAN */ ++#ifdef PNO_SUPPORT ++static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++#endif /* PNO_SUPPORT */ ++static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_info, ++ enum wl_status state, bool set); ++/* ++ * register/deregister parent device ++ */ ++static void wl_cfg80211_clear_parent_dev(void); ++ ++/* ++ * ioctl utilites ++ */ ++ ++/* ++ * cfg80211 set_wiphy_params utilities ++ */ ++static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold); ++static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold); ++static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l); ++ ++/* ++ * wl profile utilities ++ */ ++static s32 wl_update_prof(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data, s32 item); ++static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item); ++static void wl_init_prof(struct wl_priv *wl, struct net_device *ndev); ++ ++/* ++ * cfg80211 connect utilites ++ */ ++static s32 wl_set_wpa_version(struct net_device *dev, ++ struct cfg80211_connect_params *sme); ++static s32 wl_set_auth_type(struct net_device *dev, ++ struct cfg80211_connect_params *sme); ++static s32 wl_set_set_cipher(struct net_device *dev, ++ struct cfg80211_connect_params *sme); ++static s32 wl_set_key_mgmt(struct net_device *dev, ++ struct cfg80211_connect_params *sme); ++static s32 wl_set_set_sharedkey(struct net_device *dev, ++ struct cfg80211_connect_params *sme); ++#ifdef BCMWAPI_WPI ++static s32 wl_set_set_wapi_ie(struct net_device *dev, ++ struct cfg80211_connect_params *sme); ++#endif ++static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev); ++static void wl_ch_to_chanspec(int ch, ++ struct wl_join_params *join_params, size_t *join_params_size); ++ ++/* ++ * information element utilities ++ */ ++static void wl_rst_ie(struct wl_priv *wl); ++static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v); ++static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size); ++static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size); ++static u32 wl_get_ielen(struct wl_priv *wl); ++ ++#ifdef WL11U ++bcm_tlv_t * ++wl_cfg80211_find_interworking_ie(u8 *parse, u32 len); ++static s32 ++wl_cfg80211_add_iw_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag, ++ uint8 ie_id, uint8 *data, uint8 data_len); ++#endif /* WL11U */ ++ ++static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev); ++static void wl_free_wdev(struct wl_priv *wl); ++static int ++wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); ++ ++static s32 wl_inform_bss(struct wl_priv *wl); ++static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 is_roam_done); ++static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is_roam_done); ++static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy); ++s32 wl_cfg80211_channel_to_freq(u32 channel); ++ ++#if defined(DHCP_SCAN_SUPPRESS) ++static void wl_cfg80211_work_handler(struct work_struct *work); ++static void wl_cfg80211_scan_supp_timerfunc(ulong data); ++#endif /* DHCP_SCAN_SUPPRESS */ ++ ++static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, const u8 *mac_addr, ++ struct key_params *params); ++/* ++ * key indianess swap utilities ++ */ ++static void swap_key_from_BE(struct wl_wsec_key *key); ++static void swap_key_to_BE(struct wl_wsec_key *key); ++ ++/* ++ * wl_priv memory init/deinit utilities ++ */ ++static s32 wl_init_priv_mem(struct wl_priv *wl); ++static void wl_deinit_priv_mem(struct wl_priv *wl); ++ ++static void wl_delay(u32 ms); ++ ++/* ++ * ibss mode utilities ++ */ ++static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev); ++static __used bool wl_is_ibssstarter(struct wl_priv *wl); ++ ++/* ++ * link up/down , default configuration utilities ++ */ ++static s32 __wl_cfg80211_up(struct wl_priv *wl); ++static s32 __wl_cfg80211_down(struct wl_priv *wl); ++static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e); ++static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev); ++static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e); ++static void wl_link_up(struct wl_priv *wl); ++static void wl_link_down(struct wl_priv *wl); ++static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype); ++static void wl_init_conf(struct wl_conf *conf); ++ ++/* ++ * iscan handler ++ */ ++static void wl_iscan_timer(unsigned long data); ++static void wl_term_iscan(struct wl_priv *wl); ++static s32 wl_init_scan(struct wl_priv *wl); ++static s32 wl_iscan_thread(void *data); ++static s32 wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, ++ u16 action); ++static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request); ++static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan); ++static s32 wl_invoke_iscan(struct wl_priv *wl); ++static s32 wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status, ++ struct wl_scan_results **bss_list); ++static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted); ++static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan); ++static s32 wl_iscan_done(struct wl_priv *wl); ++static s32 wl_iscan_pending(struct wl_priv *wl); ++static s32 wl_iscan_inprogress(struct wl_priv *wl); ++static s32 wl_iscan_aborted(struct wl_priv *wl); ++ ++/* ++ * find most significant bit set ++ */ ++static __used u32 wl_find_msb(u16 bit16); ++ ++/* ++ * rfkill support ++ */ ++static int wl_setup_rfkill(struct wl_priv *wl, bool setup); ++static int wl_rfkill_set(void *data, bool blocked); ++ ++static wl_scan_params_t *wl_cfg80211_scan_alloc_params(int channel, ++ int nprobes, int *out_params_size); ++static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac); ++ ++/* ++ * Some external functions, TODO: move them to dhd_linux.h ++ */ ++int dhd_add_monitor(char *name, struct net_device **new_ndev); ++int dhd_del_monitor(struct net_device *ndev); ++int dhd_monitor_init(void *dhd_pub); ++int dhd_monitor_uninit(void); ++int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); ++ ++ ++ ++#define CHECK_SYS_UP(wlpriv) \ ++do { \ ++ struct net_device *ndev = wl_to_prmry_ndev(wlpriv); \ ++ if (unlikely(!wl_get_drv_status(wlpriv, READY, ndev))) { \ ++ AP6211_DEBUG("device is not ready\n"); \ ++ return -EIO; \ ++ } \ ++} while (0) ++ ++ ++#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \ ++ (akm) == RSN_AKM_UNSPECIFIED || \ ++ (akm) == RSN_AKM_PSK) ++ ++ ++extern int dhd_wait_pend8021x(struct net_device *dev); ++#ifdef PROP_TXSTATUS_VSDB ++extern int disable_proptx; ++extern int dhd_wlfc_init(dhd_pub_t *dhd); ++extern void dhd_wlfc_deinit(dhd_pub_t *dhd); ++#endif /* PROP_TXSTATUS_VSDB */ ++ ++#if (WL_DBG_LEVEL > 0) ++#define WL_DBG_ESTR_MAX 50 ++static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = { ++ "SET_SSID", "JOIN", "START", "AUTH", "AUTH_IND", ++ "DEAUTH", "DEAUTH_IND", "ASSOC", "ASSOC_IND", "REASSOC", ++ "REASSOC_IND", "DISASSOC", "DISASSOC_IND", "QUIET_START", "QUIET_END", ++ "BEACON_RX", "LINK", "MIC_ERROR", "NDIS_LINK", "ROAM", ++ "TXFAIL", "PMKID_CACHE", "RETROGRADE_TSF", "PRUNE", "AUTOAUTH", ++ "EAPOL_MSG", "SCAN_COMPLETE", "ADDTS_IND", "DELTS_IND", "BCNSENT_IND", ++ "BCNRX_MSG", "BCNLOST_MSG", "ROAM_PREP", "PFN_NET_FOUND", ++ "PFN_NET_LOST", ++ "RESET_COMPLETE", "JOIN_START", "ROAM_START", "ASSOC_START", ++ "IBSS_ASSOC", ++ "RADIO", "PSM_WATCHDOG", "WLC_E_CCX_ASSOC_START", "WLC_E_CCX_ASSOC_ABORT", ++ "PROBREQ_MSG", ++ "SCAN_CONFIRM_IND", "PSK_SUP", "COUNTRY_CODE_CHANGED", ++ "EXCEEDED_MEDIUM_TIME", "ICV_ERROR", ++ "UNICAST_DECODE_ERROR", "MULTICAST_DECODE_ERROR", "TRACE", ++ "WLC_E_BTA_HCI_EVENT", "IF", "WLC_E_P2P_DISC_LISTEN_COMPLETE", ++ "RSSI", "PFN_SCAN_COMPLETE", "WLC_E_EXTLOG_MSG", ++ "ACTION_FRAME", "ACTION_FRAME_COMPLETE", "WLC_E_PRE_ASSOC_IND", ++ "WLC_E_PRE_REASSOC_IND", "WLC_E_CHANNEL_ADOPTED", "WLC_E_AP_STARTED", ++ "WLC_E_DFS_AP_STOP", "WLC_E_DFS_AP_RESUME", "WLC_E_WAI_STA_EVENT", ++ "WLC_E_WAI_MSG", "WLC_E_ESCAN_RESULT", "WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE", ++ "WLC_E_PROBRESP_MSG", "WLC_E_P2P_PROBREQ_MSG", "WLC_E_DCS_REQUEST", "WLC_E_FIFO_CREDIT_MAP", ++ "WLC_E_ACTION_FRAME_RX", "WLC_E_WAKE_EVENT", "WLC_E_RM_COMPLETE" ++}; ++#endif /* WL_DBG_LEVEL */ ++ ++#define CHAN2G(_channel, _freq, _flags) { \ ++ .band = IEEE80211_BAND_2GHZ, \ ++ .center_freq = (_freq), \ ++ .hw_value = (_channel), \ ++ .flags = (_flags), \ ++ .max_antenna_gain = 0, \ ++ .max_power = 30, \ ++} ++ ++#define CHAN5G(_channel, _flags) { \ ++ .band = IEEE80211_BAND_5GHZ, \ ++ .center_freq = 5000 + (5 * (_channel)), \ ++ .hw_value = (_channel), \ ++ .flags = (_flags), \ ++ .max_antenna_gain = 0, \ ++ .max_power = 30, \ ++} ++ ++#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2) ++#define RATETAB_ENT(_rateid, _flags) \ ++ { \ ++ .bitrate = RATE_TO_BASE100KBPS(_rateid), \ ++ .hw_value = (_rateid), \ ++ .flags = (_flags), \ ++ } ++ ++static struct ieee80211_rate __wl_rates[] = { ++ RATETAB_ENT(WLC_RATE_1M, 0), ++ RATETAB_ENT(WLC_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE), ++ RATETAB_ENT(WLC_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE), ++ RATETAB_ENT(WLC_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE), ++ RATETAB_ENT(WLC_RATE_6M, 0), ++ RATETAB_ENT(WLC_RATE_9M, 0), ++ RATETAB_ENT(WLC_RATE_12M, 0), ++ RATETAB_ENT(WLC_RATE_18M, 0), ++ RATETAB_ENT(WLC_RATE_24M, 0), ++ RATETAB_ENT(WLC_RATE_36M, 0), ++ RATETAB_ENT(WLC_RATE_48M, 0), ++ RATETAB_ENT(WLC_RATE_54M, 0) ++}; ++ ++#define wl_a_rates (__wl_rates + 4) ++#define wl_a_rates_size 8 ++#define wl_g_rates (__wl_rates + 0) ++#define wl_g_rates_size 12 ++ ++static struct ieee80211_channel __wl_2ghz_channels[] = { ++ CHAN2G(1, 2412, 0), ++ CHAN2G(2, 2417, 0), ++ CHAN2G(3, 2422, 0), ++ CHAN2G(4, 2427, 0), ++ CHAN2G(5, 2432, 0), ++ CHAN2G(6, 2437, 0), ++ CHAN2G(7, 2442, 0), ++ CHAN2G(8, 2447, 0), ++ CHAN2G(9, 2452, 0), ++ CHAN2G(10, 2457, 0), ++ CHAN2G(11, 2462, 0), ++ CHAN2G(12, 2467, 0), ++ CHAN2G(13, 2472, 0), ++ CHAN2G(14, 2484, 0) ++}; ++ ++static struct ieee80211_channel __wl_5ghz_a_channels[] = { ++ CHAN5G(34, 0), CHAN5G(36, 0), ++ CHAN5G(38, 0), CHAN5G(40, 0), ++ CHAN5G(42, 0), CHAN5G(44, 0), ++ CHAN5G(46, 0), CHAN5G(48, 0), ++ CHAN5G(52, 0), CHAN5G(56, 0), ++ CHAN5G(60, 0), CHAN5G(64, 0), ++ CHAN5G(100, 0), CHAN5G(104, 0), ++ CHAN5G(108, 0), CHAN5G(112, 0), ++ CHAN5G(116, 0), CHAN5G(120, 0), ++ CHAN5G(124, 0), CHAN5G(128, 0), ++ CHAN5G(132, 0), CHAN5G(136, 0), ++ CHAN5G(140, 0), CHAN5G(149, 0), ++ CHAN5G(153, 0), CHAN5G(157, 0), ++ CHAN5G(161, 0), CHAN5G(165, 0) ++}; ++ ++static struct ieee80211_supported_band __wl_band_2ghz = { ++ .band = IEEE80211_BAND_2GHZ, ++ .channels = __wl_2ghz_channels, ++ .n_channels = ARRAY_SIZE(__wl_2ghz_channels), ++ .bitrates = wl_g_rates, ++ .n_bitrates = wl_g_rates_size ++}; ++ ++static struct ieee80211_supported_band __wl_band_5ghz_a = { ++ .band = IEEE80211_BAND_5GHZ, ++ .channels = __wl_5ghz_a_channels, ++ .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), ++ .bitrates = wl_a_rates, ++ .n_bitrates = wl_a_rates_size ++}; ++ ++static const u32 __wl_cipher_suites[] = { ++ WLAN_CIPHER_SUITE_WEP40, ++ WLAN_CIPHER_SUITE_WEP104, ++ WLAN_CIPHER_SUITE_TKIP, ++ WLAN_CIPHER_SUITE_CCMP, ++ WLAN_CIPHER_SUITE_AES_CMAC, ++#ifdef BCMWAPI_WPI ++ WLAN_CIPHER_SUITE_SMS4 ++#endif ++}; ++ ++ ++/* IOCtl version read from targeted driver */ ++static int ioctl_version; ++ ++/* Return a new chanspec given a legacy chanspec ++ * Returns INVCHANSPEC on error ++ */ ++static chanspec_t ++wl_chspec_from_legacy(chanspec_t legacy_chspec) ++{ ++ chanspec_t chspec; ++ ++ /* get the channel number */ ++ chspec = LCHSPEC_CHANNEL(legacy_chspec); ++ ++ /* convert the band */ ++ if (LCHSPEC_IS2G(legacy_chspec)) { ++ chspec |= WL_CHANSPEC_BAND_2G; ++ } else { ++ chspec |= WL_CHANSPEC_BAND_5G; ++ } ++ ++ /* convert the bw and sideband */ ++ if (LCHSPEC_IS20(legacy_chspec)) { ++ chspec |= WL_CHANSPEC_BW_20; ++ } else { ++ chspec |= WL_CHANSPEC_BW_40; ++ if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) { ++ chspec |= WL_CHANSPEC_CTL_SB_L; ++ } else { ++ chspec |= WL_CHANSPEC_CTL_SB_U; ++ } ++ } ++ ++ if (wf_chspec_malformed(chspec)) { ++ AP6211_ERR("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n", ++ chspec); ++ return INVCHANSPEC; ++ } ++ ++ return chspec; ++} ++ ++/* Return a legacy chanspec given a new chanspec ++ * Returns INVCHANSPEC on error ++ */ ++static chanspec_t ++wl_chspec_to_legacy(chanspec_t chspec) ++{ ++ chanspec_t lchspec; ++ ++ if (wf_chspec_malformed(chspec)) { ++ AP6211_ERR("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n", ++ chspec); ++ return INVCHANSPEC; ++ } ++ ++ /* get the channel number */ ++ lchspec = CHSPEC_CHANNEL(chspec); ++ ++ /* convert the band */ ++ if (CHSPEC_IS2G(chspec)) { ++ lchspec |= WL_LCHANSPEC_BAND_2G; ++ } else { ++ lchspec |= WL_LCHANSPEC_BAND_5G; ++ } ++ ++ /* convert the bw and sideband */ ++ if (CHSPEC_IS20(chspec)) { ++ lchspec |= WL_LCHANSPEC_BW_20; ++ lchspec |= WL_LCHANSPEC_CTL_SB_NONE; ++ } else if (CHSPEC_IS40(chspec)) { ++ lchspec |= WL_LCHANSPEC_BW_40; ++ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) { ++ lchspec |= WL_LCHANSPEC_CTL_SB_LOWER; ++ } else { ++ lchspec |= WL_LCHANSPEC_CTL_SB_UPPER; ++ } ++ } else { ++ /* cannot express the bandwidth */ ++ char chanbuf[CHANSPEC_STR_LEN]; ++ AP6211_ERR( ++ "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) " ++ "to pre-11ac format\n", ++ wf_chspec_ntoa(chspec, chanbuf), chspec); ++ return INVCHANSPEC; ++ } ++ ++ return lchspec; ++} ++ ++/* given a chanspec value, do the endian and chanspec version conversion to ++ * a chanspec_t value ++ * Returns INVCHANSPEC on error ++ */ ++static chanspec_t ++wl_chspec_host_to_driver(chanspec_t chanspec) ++{ ++ if (ioctl_version == 1) { ++ chanspec = wl_chspec_to_legacy(chanspec); ++ if (chanspec == INVCHANSPEC) { ++ return chanspec; ++ } ++ } ++ chanspec = htodchanspec(chanspec); ++ ++ return chanspec; ++} ++ ++/* given a channel value, do the endian and chanspec version conversion to ++ * a chanspec_t value ++ * Returns INVCHANSPEC on error ++ */ ++chanspec_t ++wl_ch_host_to_driver(u16 channel) ++{ ++ ++ chanspec_t chanspec; ++ ++ chanspec = channel & WL_CHANSPEC_CHAN_MASK; ++ ++ if (channel <= CH_MAX_2G_CHANNEL) ++ chanspec |= WL_CHANSPEC_BAND_2G; ++ else ++ chanspec |= WL_CHANSPEC_BAND_5G; ++ ++ chanspec |= WL_CHANSPEC_BW_20; ++ chanspec |= WL_CHANSPEC_CTL_SB_NONE; ++ ++ return wl_chspec_host_to_driver(chanspec); ++} ++ ++/* given a chanspec value from the driver, do the endian and chanspec version conversion to ++ * a chanspec_t value ++ * Returns INVCHANSPEC on error ++ */ ++static chanspec_t ++wl_chspec_driver_to_host(chanspec_t chanspec) ++{ ++ chanspec = dtohchanspec(chanspec); ++ if (ioctl_version == 1) { ++ chanspec = wl_chspec_from_legacy(chanspec); ++ } ++ ++ return chanspec; ++} ++ ++/* There isn't a lot of sense in it, but you can transmit anything you like */ ++static const struct ieee80211_txrx_stypes ++wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { ++ [NL80211_IFTYPE_ADHOC] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_STATION] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) ++ }, ++ [NL80211_IFTYPE_AP] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | ++ BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_AP_VLAN] = { ++ /* copy AP */ ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | ++ BIT(IEEE80211_STYPE_ACTION >> 4) ++ }, ++ [NL80211_IFTYPE_P2P_CLIENT] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) ++ }, ++ [NL80211_IFTYPE_P2P_GO] = { ++ .tx = 0xffff, ++ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | ++ BIT(IEEE80211_STYPE_ACTION >> 4) ++ } ++}; ++ ++static void swap_key_from_BE(struct wl_wsec_key *key) ++{ ++ key->index = htod32(key->index); ++ key->len = htod32(key->len); ++ key->algo = htod32(key->algo); ++ key->flags = htod32(key->flags); ++ key->rxiv.hi = htod32(key->rxiv.hi); ++ key->rxiv.lo = htod16(key->rxiv.lo); ++ key->iv_initialized = htod32(key->iv_initialized); ++} ++ ++static void swap_key_to_BE(struct wl_wsec_key *key) ++{ ++ key->index = dtoh32(key->index); ++ key->len = dtoh32(key->len); ++ key->algo = dtoh32(key->algo); ++ key->flags = dtoh32(key->flags); ++ key->rxiv.hi = dtoh32(key->rxiv.hi); ++ key->rxiv.lo = dtoh16(key->rxiv.lo); ++ key->iv_initialized = dtoh32(key->iv_initialized); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) ++/* For debug: Dump the contents of the encoded wps ie buffe */ ++static void ++wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc) ++{ ++ #define WPS_IE_FIXED_LEN 6 ++ u16 len; ++ u8 *subel = NULL; ++ u16 subelt_id; ++ u16 subelt_len; ++ u16 val; ++ u8 *valptr = (uint8*) &val; ++ if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) { ++ AP6211_ERR("invalid argument : NULL\n")); ++ return; ++ } ++ len = (u16)wps_ie[TLV_LEN_OFF]; ++ ++ if (len > wps_ie_len) { ++ AP6211_ERR("invalid length len %d, wps ie len %d\n", len, wps_ie_len); ++ return; ++ } ++ AP6211_DEBUG("wps_ie len=%d\n", len); ++ len -= 4; /* for the WPS IE's OUI, oui_type fields */ ++ subel = wps_ie + WPS_IE_FIXED_LEN; ++ while (len >= 4) { /* must have attr id, attr len fields */ ++ valptr[0] = *subel++; ++ valptr[1] = *subel++; ++ subelt_id = HTON16(val); ++ ++ valptr[0] = *subel++; ++ valptr[1] = *subel++; ++ subelt_len = HTON16(val); ++ ++ len -= 4; /* for the attr id, attr len fields */ ++ len -= subelt_len; /* for the remaining fields in this attribute */ ++ AP6211_DEBUG(" subel=%p, subelt_id=0x%x subelt_len=%u\n", ++ subel, subelt_id, subelt_len); ++ ++ if (subelt_id == WPS_ID_VERSION) { ++ AP6211_DEBUG(" attr WPS_ID_VERSION: %u\n", *subel); ++ } else if (subelt_id == WPS_ID_REQ_TYPE) { ++ AP6211_DEBUG(" attr WPS_ID_REQ_TYPE: %u\n", *subel); ++ } else if (subelt_id == WPS_ID_CONFIG_METHODS) { ++ valptr[0] = *subel; ++ valptr[1] = *(subel + 1); ++ AP6211_DEBUG(" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val)); ++ } else if (subelt_id == WPS_ID_DEVICE_NAME) { ++ char devname[100]; ++ memcpy(devname, subel, subelt_len); ++ devname[subelt_len] = '\0'; ++ AP6211_DEBUG(" attr WPS_ID_DEVICE_NAME: %s (len %u)\n", ++ devname, subelt_len); ++ } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) { ++ valptr[0] = *subel; ++ valptr[1] = *(subel + 1); ++ AP6211_DEBUG(" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val)); ++ *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false; ++ } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) { ++ valptr[0] = *subel; ++ valptr[1] = *(subel + 1); ++ AP6211_DEBUG(" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val)); ++ valptr[0] = *(subel + 6); ++ valptr[1] = *(subel + 7); ++ AP6211_DEBUG(" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val)); ++ } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) { ++ valptr[0] = *subel; ++ valptr[1] = *(subel + 1); ++ AP6211_DEBUG(" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val)); ++ valptr[0] = *(subel + 6); ++ valptr[1] = *(subel + 7); ++ AP6211_DEBUG(" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val)); ++ } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) { ++ valptr[0] = *subel; ++ valptr[1] = *(subel + 1); ++ AP6211_DEBUG(" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS" ++ ": cat=%u\n", HTON16(val)); ++ } else { ++ AP6211_DEBUG(" unknown attr 0x%x\n", subelt_id); ++ } ++ ++ subel += subelt_len; ++ } ++} ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ ++ ++static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) ++{ ++ chanspec_t chspec; ++ int err = 0; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct net_device *dev = wl_to_prmry_ndev(wl); ++ struct ether_addr bssid; ++ struct wl_bss_info *bss = NULL; ++ ++ if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) { ++ /* STA interface is not associated. So start the new interface on a temp ++ * channel . Later proper channel will be applied by the above framework ++ * via set_channel (cfg80211 API). ++ */ ++ AP6211_DEBUG("Not associated. Return a temp channel. \n"); ++ return wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); ++ } ++ ++ ++ *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); ++ if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf, ++ WL_EXTRA_BUF_MAX, false))) { ++ AP6211_ERR("Failed to get associated bss info, use temp channel \n"); ++ chspec = wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); ++ } ++ else { ++ bss = (struct wl_bss_info *) (wl->extra_buf + 4); ++ chspec = bss->chanspec; ++ AP6211_DEBUG("Valid BSS Found. chanspec:%d \n", chspec); ++ } ++ return chspec; ++} ++ ++static struct net_device* wl_cfg80211_add_monitor_if(char *name) ++{ ++#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) ++ AP6211_DEBUG("wl_cfg80211_add_monitor_if: No more support monitor interface\n"); ++ return ERR_PTR(-EOPNOTSUPP); ++#else ++ struct net_device* ndev = NULL; ++ ++ dhd_add_monitor(name, &ndev); ++ AP6211_DEBUG("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev); ++ return ndev; ++#endif /* defined(WLP2P) && defined(WL_ENABLE_P2P_IF) */ ++} ++ ++static struct net_device * ++wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, ++ enum nl80211_iftype type, u32 *flags, ++ struct vif_params *params) ++{ ++ s32 err; ++ s32 timeout = -1; ++ s32 wlif_type = -1; ++ s32 mode = 0; ++ s32 val = 0; ++ s32 dhd_mode = 0; ++ chanspec_t chspec; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct net_device *_ndev; ++ struct ether_addr primary_mac; ++ int (*net_attach)(void *dhdp, int ifidx); ++ bool rollback_lock = false; ++#ifdef PROP_TXSTATUS_VSDB ++ s32 up = 1; ++ dhd_pub_t *dhd; ++#endif /* PROP_TXSTATUS_VSDB */ ++ ++ if (!wl) ++ return ERR_PTR(-EINVAL); ++ ++#ifdef PROP_TXSTATUS_VSDB ++ dhd = (dhd_pub_t *)(wl->pub); ++#endif /* PROP_TXSTATUS_VSDB */ ++ ++ ++ /* Use primary I/F for sending cmds down to firmware */ ++ _ndev = wl_to_prmry_ndev(wl); ++ ++ AP6211_DEBUG("if name: %s, type: %d\n", name, type); ++ switch (type) { ++ case NL80211_IFTYPE_ADHOC: ++ case NL80211_IFTYPE_AP_VLAN: ++ case NL80211_IFTYPE_WDS: ++ case NL80211_IFTYPE_MESH_POINT: ++ AP6211_ERR("Unsupported interface type\n"); ++ mode = WL_MODE_IBSS; ++ return NULL; ++ case NL80211_IFTYPE_MONITOR: ++ return wl_cfg80211_add_monitor_if(name); ++ case NL80211_IFTYPE_P2P_CLIENT: ++ case NL80211_IFTYPE_STATION: ++ wlif_type = WL_P2P_IF_CLIENT; ++ mode = WL_MODE_BSS; ++ break; ++ case NL80211_IFTYPE_P2P_GO: ++ case NL80211_IFTYPE_AP: ++ wlif_type = WL_P2P_IF_GO; ++ mode = WL_MODE_AP; ++ break; ++ default: ++ AP6211_ERR("Unsupported interface type\n"); ++ return NULL; ++ break; ++ } ++ ++ if (!name) { ++ AP6211_ERR("name is NULL\n"); ++ return NULL; ++ } ++ if (wl->p2p_supported && (wlif_type != -1)) { ++ if (wl_get_p2p_status(wl, IF_DELETING)) { ++ /* wait till IF_DEL is complete ++ * release the lock for the unregister to proceed ++ */ ++ if (rtnl_is_locked()) { ++ rtnl_unlock(); ++ rollback_lock = true; ++ } ++ AP6211_DEBUG("%s: Released the lock and wait till IF_DEL is complete\n", ++ __func__); ++ timeout = wait_event_interruptible_timeout(wl->netif_change_event, ++ (wl_get_p2p_status(wl, IF_DELETING) == false), ++ msecs_to_jiffies(MAX_WAIT_TIME)); ++ ++ /* put back the rtnl_lock again */ ++ if (rollback_lock) { ++ rtnl_lock(); ++ rollback_lock = false; ++ } ++ if (timeout > 0) { ++ AP6211_ERR("IF DEL is Success\n"); ++ ++ } else { ++ AP6211_ERR("timeount < 0, return -EAGAIN\n"); ++ return ERR_PTR(-EAGAIN); ++ } ++ /* It should be now be safe to put this check here since we are sure ++ * by now netdev_notifier (unregister) would have been called ++ */ ++ if (wl->iface_cnt == IFACE_MAX_CNT) ++ return ERR_PTR(-ENOMEM); ++ } ++ ++#ifdef PROP_TXSTATUS_VSDB ++ if (!dhd) ++ return ERR_PTR(-ENODEV); ++#endif /* PROP_TXSTATUS_VSDB */ ++ if (!wl->p2p) ++ return ERR_PTR(-ENODEV); ++ ++ if (wl->p2p && !wl->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) { ++ p2p_on(wl) = true; ++ wl_cfgp2p_set_firm_p2p(wl); ++ wl_cfgp2p_init_discovery(wl); ++ get_primary_mac(wl, &primary_mac); ++ wl_cfgp2p_generate_bss_mac(&primary_mac, ++ &wl->p2p->dev_addr, &wl->p2p->int_addr); ++ } ++ ++ memset(wl->p2p->vir_ifname, 0, IFNAMSIZ); ++ strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1); ++ ++ wl_notify_escan_complete(wl, _ndev, true, true); ++#ifdef PROP_TXSTATUS_VSDB ++ if (!wl->wlfc_on && !disable_proptx) { ++ dhd->wlfc_enabled = true; ++ dhd_wlfc_init(dhd); ++ err = wldev_ioctl(_ndev, WLC_UP, &up, sizeof(s32), true); ++ if (err < 0) ++ AP6211_ERR("WLC_UP return err:%d\n", err); ++ wl->wlfc_on = true; ++ } ++#endif /* PROP_TXSTATUS_VSDB */ ++ ++ /* In concurrency case, STA may be already associated in a particular channel. ++ * so retrieve the current channel of primary interface and then start the virtual ++ * interface on that. ++ */ ++ chspec = wl_cfg80211_get_shared_freq(wiphy); ++ ++ /* For P2P mode, use P2P-specific driver features to create the ++ * bss: "wl p2p_ifadd" ++ */ ++ wl_set_p2p_status(wl, IF_ADD); ++ if (wlif_type == WL_P2P_IF_GO) ++ wldev_iovar_setint(_ndev, "mpc", 0); ++ err = wl_cfgp2p_ifadd(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec); ++ ++ if (unlikely(err)) { ++ AP6211_ERR(" virtual iface add failed (%d) \n", err); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ timeout = wait_event_interruptible_timeout(wl->netif_change_event, ++ (wl_get_p2p_status(wl, IF_ADD) == false), ++ msecs_to_jiffies(MAX_WAIT_TIME)); ++ if (timeout > 0 && (!wl_get_p2p_status(wl, IF_ADD))) { ++ ++ struct wireless_dev *vwdev; ++ vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL); ++ if (unlikely(!vwdev)) { ++ AP6211_ERR("Could not allocate wireless device\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ vwdev->wiphy = wl->wdev->wiphy; ++ AP6211_DEBUG(" virtual interface(%s) is created memalloc done \n", ++ wl->p2p->vir_ifname); ++ vwdev->iftype = type; ++ _ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); ++ _ndev->ieee80211_ptr = vwdev; ++ SET_NETDEV_DEV(_ndev, wiphy_dev(vwdev->wiphy)); ++ vwdev->netdev = _ndev; ++ wl_set_drv_status(wl, READY, _ndev); ++ wl->p2p->vif_created = true; ++ wl_set_mode_by_netdev(wl, _ndev, mode); ++ net_attach = wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION); ++ if (rtnl_is_locked()) { ++ rtnl_unlock(); ++ rollback_lock = true; ++ } ++ if (net_attach && !net_attach(wl->pub, _ndev->ifindex)) { ++ wl_alloc_netinfo(wl, _ndev, vwdev, mode, PM_ENABLE); ++ val = 1; ++ /* Disable firmware roaming for P2P interface */ ++ wldev_iovar_setint(_ndev, "roam_off", val); ++ AP6211_ERR(" virtual interface(%s) is " ++ "created net attach done\n", wl->p2p->vir_ifname); ++ if (mode == WL_MODE_AP) ++ wl_set_drv_status(wl, CONNECTED, _ndev); ++ if (type == NL80211_IFTYPE_P2P_CLIENT) ++ dhd_mode = DHD_FLAG_P2P_GC_MODE; ++ else if (type == NL80211_IFTYPE_P2P_GO) ++ dhd_mode = DHD_FLAG_P2P_GO_MODE; ++ DNGL_FUNC(dhd_cfg80211_set_p2p_info, (wl, dhd_mode)); ++ } else { ++ /* put back the rtnl_lock again */ ++ if (rollback_lock) ++ rtnl_lock(); ++ goto fail; ++ } ++ /* put back the rtnl_lock again */ ++ if (rollback_lock) ++ rtnl_lock(); ++ return _ndev; ++ ++ } else { ++ wl_clr_p2p_status(wl, IF_ADD); ++ AP6211_ERR(" virtual interface(%s) is not created \n", wl->p2p->vir_ifname); ++ memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ); ++ wl->p2p->vif_created = false; ++#ifdef PROP_TXSTATUS_VSDB ++ if (dhd->wlfc_enabled && wl->wlfc_on) { ++ dhd->wlfc_enabled = false; ++ dhd_wlfc_deinit(dhd); ++ wl->wlfc_on = false; ++ } ++#endif /* PROP_TXSTATUS_VSDB */ ++ } ++ } ++fail: ++ if (wlif_type == WL_P2P_IF_GO) ++ wldev_iovar_setint(_ndev, "mpc", 1); ++ return ERR_PTR(-ENODEV); ++} ++ ++static s32 ++wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) ++{ ++ struct ether_addr p2p_mac; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ s32 timeout = -1; ++ s32 ret = 0; ++ AP6211_DEBUG("Enter\n"); ++ ++ if (wl->p2p_net == dev) { ++ /* Since there is no ifidx corresponding to p2p0, cmds to ++ * firmware should be routed through primary I/F ++ */ ++ dev = wl_to_prmry_ndev(wl); ++ } ++ ++ if (wl->p2p_supported) { ++ memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN); ++ ++ /* Clear GO_NEG_PHASE bit to take care of GO-NEG-FAIL cases ++ */ ++ AP6211_DEBUG("P2P: GO_NEG_PHASE status cleared "); ++ wl_clr_p2p_status(wl, GO_NEG_PHASE); ++ if (wl->p2p->vif_created) { ++ if (wl_get_drv_status(wl, SCANNING, dev)) { ++ wl_notify_escan_complete(wl, dev, true, true); ++ } ++ wldev_iovar_setint(dev, "mpc", 1); ++ ++ /* for GC */ ++ if (wl_get_drv_status(wl, DISCONNECTING, dev) && ++ (wl_get_mode_by_netdev(wl, dev) != WL_MODE_AP)) { ++ AP6211_ERR("Wait for Link Down event for GC !\n"); ++ wait_for_completion_timeout ++ (&wl->iface_disable, msecs_to_jiffies(500)); ++ } ++ wl_set_p2p_status(wl, IF_DELETING); ++ DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (wl)); ++ ++ /* for GO */ ++ if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) { ++ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false); ++ /* disable interface before bsscfg free */ ++ ret = wl_cfgp2p_ifdisable(wl, &p2p_mac); ++ /* if fw doesn't support "ifdis", ++ do not wait for link down of ap mode ++ */ ++ if (ret == 0) { ++ AP6211_ERR("Wait for Link Down event for GO !!!\n"); ++ wait_for_completion_timeout(&wl->iface_disable, ++ msecs_to_jiffies(500)); ++ } else { ++ msleep(300); ++ } ++ } ++ wl_cfgp2p_clear_management_ie(wl, wl_cfgp2p_find_idx(wl, dev)); ++ /* delete interface after link down */ ++ ret = wl_cfgp2p_ifdel(wl, &p2p_mac); ++ /* Firmware could not delete the interface so we will not get WLC_E_IF ++ * event for cleaning the dhd virtual nw interace ++ * So lets do it here. Failures from fw will ensure the application to do ++ * ifconfig down and up sequnce, which will reload the fw ++ * however we should cleanup the linux network virtual interfaces ++ */ ++ /* Request framework to RESET and clean up */ ++ if (ret) { ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ AP6211_ERR("Firmware returned an error (%d) from p2p_ifdel" ++ "HANG Notification sent to %s\n", ret, ndev->name); ++ net_os_send_hang_message(ndev); ++ } ++ /* Wait for IF_DEL operation to be finished in firmware */ ++ timeout = wait_event_interruptible_timeout(wl->netif_change_event, ++ (wl->p2p->vif_created == false), ++ msecs_to_jiffies(MAX_WAIT_TIME)); ++ if (timeout > 0 && (wl->p2p->vif_created == false)) { ++ AP6211_DEBUG("IFDEL operation done\n"); ++ } else { ++ AP6211_ERR("IFDEL didn't complete properly\n"); ++ } ++ ret = dhd_del_monitor(dev); ++ } ++ } ++ return ret; ++} ++ ++static s32 ++wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, ++ enum nl80211_iftype type, u32 *flags, ++ struct vif_params *params) ++{ ++ s32 ap = 0; ++ s32 infra = 0; ++ s32 wlif_type; ++ s32 mode = 0; ++ chanspec_t chspec; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); ++ AP6211_DEBUG("Enter type %d\n", type); ++ switch (type) { ++ case NL80211_IFTYPE_MONITOR: ++ case NL80211_IFTYPE_WDS: ++ case NL80211_IFTYPE_MESH_POINT: ++ ap = 1; ++ AP6211_ERR("type (%d) : currently we do not support this type\n", ++ type); ++ break; ++ case NL80211_IFTYPE_ADHOC: ++ mode = WL_MODE_IBSS; ++ break; ++ case NL80211_IFTYPE_STATION: ++ case NL80211_IFTYPE_P2P_CLIENT: ++ mode = WL_MODE_BSS; ++ infra = 1; ++ break; ++ case NL80211_IFTYPE_AP: ++ case NL80211_IFTYPE_AP_VLAN: ++ case NL80211_IFTYPE_P2P_GO: ++ mode = WL_MODE_AP; ++ ap = 1; ++ break; ++ default: ++ return -EINVAL; ++ } ++ if (!dhd) ++ return -EINVAL; ++ if (ap) { ++ wl_set_mode_by_netdev(wl, ndev, mode); ++ if (wl->p2p_supported && wl->p2p->vif_created) { ++ AP6211_DEBUG("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p->vif_created, ++ p2p_on(wl)); ++ wldev_iovar_setint(ndev, "mpc", 0); ++ wl_notify_escan_complete(wl, ndev, true, true); ++ ++ /* In concurrency case, STA may be already associated in a particular ++ * channel. so retrieve the current channel of primary interface and ++ * then start the virtual interface on that. ++ */ ++ chspec = wl_cfg80211_get_shared_freq(wiphy); ++ ++ wlif_type = WL_P2P_IF_GO; ++ AP6211_ERR("%s : ap (%d), infra (%d), iftype: (%d)\n", ++ ndev->name, ap, infra, type); ++ wl_set_p2p_status(wl, IF_CHANGING); ++ wl_clr_p2p_status(wl, IF_CHANGED); ++ wl_cfgp2p_ifchange(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec); ++ wait_event_interruptible_timeout(wl->netif_change_event, ++ (wl_get_p2p_status(wl, IF_CHANGED) == true), ++ msecs_to_jiffies(MAX_WAIT_TIME)); ++ wl_set_mode_by_netdev(wl, ndev, mode); ++ dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE; ++ dhd->op_mode |= DHD_FLAG_P2P_GO_MODE; ++ wl_clr_p2p_status(wl, IF_CHANGING); ++ wl_clr_p2p_status(wl, IF_CHANGED); ++ if (mode == WL_MODE_AP) ++ wl_set_drv_status(wl, CONNECTED, ndev); ++ } else if (ndev == wl_to_prmry_ndev(wl) && ++ !wl_get_drv_status(wl, AP_CREATED, ndev)) { ++ wl_set_drv_status(wl, AP_CREATING, ndev); ++ if (!wl->ap_info && ++ !(wl->ap_info = kzalloc(sizeof(struct ap_info), GFP_KERNEL))) { ++ AP6211_ERR("struct ap_saved_ie allocation failed\n"); ++ return -ENOMEM; ++ } ++ } else { ++ AP6211_ERR("Cannot change the interface for GO or SOFTAP\n"); ++ return -EINVAL; ++ } ++ } else { ++ AP6211_DEBUG("Change_virtual_iface for transition from GO/AP to client/STA"); ++ } ++ ++ ndev->ieee80211_ptr->iftype = type; ++ return 0; ++} ++ ++s32 ++wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx, ++ void* _net_attach) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ s32 ret = BCME_OK; ++ AP6211_DEBUG("Enter"); ++ if (!ndev) { ++ AP6211_ERR("net is NULL\n"); ++ return 0; ++ } ++ if (wl->p2p_supported && wl_get_p2p_status(wl, IF_ADD)) { ++ AP6211_DEBUG("IF_ADD event called from dongle, old interface name: %s," ++ "new name: %s\n", ndev->name, wl->p2p->vir_ifname); ++ /* Assign the net device to CONNECT BSSCFG */ ++ strncpy(ndev->name, wl->p2p->vir_ifname, IFNAMSIZ - 1); ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = ndev; ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = bssidx; ++ wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION) = _net_attach; ++ ndev->ifindex = idx; ++ wl_clr_p2p_status(wl, IF_ADD); ++ ++ wake_up_interruptible(&wl->netif_change_event); ++ } else { ++ ret = BCME_NOTREADY; ++ } ++ return ret; ++} ++ ++s32 ++wl_cfg80211_notify_ifdel(void) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ ++ AP6211_DEBUG("Enter \n"); ++ wl_clr_p2p_status(wl, IF_DELETING); ++ wake_up_interruptible(&wl->netif_change_event); ++ return 0; ++} ++ ++s32 ++wl_cfg80211_ifdel_ops(struct net_device *ndev) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ bool rollback_lock = false; ++ s32 index = 0; ++#ifdef PROP_TXSTATUS_VSDB ++ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); ++#endif /* PROP_TXSTATUS_VSDB */ ++ if (!ndev || (strlen(ndev->name) == 0)) { ++ AP6211_ERR("net is NULL\n"); ++ return 0; ++ } ++ ++ if (p2p_is_on(wl) && wl->p2p->vif_created && ++ wl_get_p2p_status(wl, IF_DELETING)) { ++ if (wl->scan_request && ++ (wl->escan_info.ndev == ndev)) { ++ /* Abort any pending scan requests */ ++ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; ++ if (!rtnl_is_locked()) { ++ rtnl_lock(); ++ rollback_lock = true; ++ } ++ AP6211_DEBUG("ESCAN COMPLETED\n"); ++ wl_notify_escan_complete(wl, ndev, true, false); ++ if (rollback_lock) ++ rtnl_unlock(); ++ } ++ AP6211_ERR("IF_DEL event called from dongle, net %x, vif name: %s\n", ++ (unsigned int)ndev, wl->p2p->vir_ifname); ++ ++ memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ); ++ index = wl_cfgp2p_find_idx(wl, ndev); ++ wl_to_p2p_bss_ndev(wl, index) = NULL; ++ wl_to_p2p_bss_bssidx(wl, index) = WL_INVALID; ++ wl->p2p->vif_created = false; ++ ++ AP6211_DEBUG("index : %d\n", index); ++#ifdef PROP_TXSTATUS_VSDB ++ if (dhd->wlfc_enabled && wl->wlfc_on) { ++ dhd->wlfc_enabled = false; ++ dhd_wlfc_deinit(dhd); ++ wl->wlfc_on = false; ++ } ++#endif /* PROP_TXSTATUS_VSDB */ ++ wl_clr_drv_status(wl, CONNECTED, ndev); ++ } ++ /* Wake up any waiting thread */ ++ wake_up_interruptible(&wl->netif_change_event); ++ ++ return 0; ++} ++ ++s32 ++wl_cfg80211_is_progress_ifadd(void) ++{ ++ s32 is_progress = 0; ++ struct wl_priv *wl = wlcfg_drv_priv; ++ if (wl_get_p2p_status(wl, IF_ADD)) ++ is_progress = 1; ++ return is_progress; ++} ++ ++s32 ++wl_cfg80211_is_progress_ifchange(void) ++{ ++ s32 is_progress = 0; ++ struct wl_priv *wl = wlcfg_drv_priv; ++ if (wl_get_p2p_status(wl, IF_CHANGING)) ++ is_progress = 1; ++ return is_progress; ++} ++ ++ ++s32 ++wl_cfg80211_notify_ifchange(void) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ if (wl_get_p2p_status(wl, IF_CHANGING)) { ++ wl_set_p2p_status(wl, IF_CHANGED); ++ wake_up_interruptible(&wl->netif_change_event); ++ } ++ return 0; ++} ++ ++/* Find listen channel */ ++static s32 wl_find_listen_channel(struct wl_priv *wl, ++ u8 *ie, u32 ie_len) ++{ ++ wifi_p2p_ie_t *p2p_ie; ++ u8 *end, *pos; ++ s32 listen_channel; ++ ++ p2p_ie = wl_cfgp2p_find_p2pie(ie, ie_len); ++ ++ if (p2p_ie == NULL) ++ return 0; ++ ++ pos = p2p_ie->subelts; ++ end = p2p_ie->subelts + (p2p_ie->len - 4); ++ ++ AP6211_DEBUG(" found p2p ie ! lenth %d \n", ++ p2p_ie->len); ++ ++ while (pos < end) { ++ uint16 attr_len; ++ if (pos + 2 >= end) { ++ AP6211_DEBUG(" -- Invalid P2P attribute"); ++ return 0; ++ } ++ attr_len = ((uint16) (((pos + 1)[1] << 8) | (pos + 1)[0])); ++ ++ if (pos + 3 + attr_len > end) { ++ AP6211_DEBUG("P2P: Attribute underflow " ++ "(len=%u left=%d)", ++ attr_len, (int) (end - pos - 3)); ++ return 0; ++ } ++ ++ /* if Listen Channel att id is 6 and the vailue is valid, ++ * return the listen channel ++ */ ++ if (pos[0] == 6) { ++ /* listen channel subel length format ++ * 1(id) + 2(len) + 3(country) + 1(op. class) + 1(chan num) ++ */ ++ listen_channel = pos[1 + 2 + 3 + 1]; ++ ++ if (listen_channel == SOCIAL_CHAN_1 || ++ listen_channel == SOCIAL_CHAN_2 || ++ listen_channel == SOCIAL_CHAN_3) { ++ AP6211_DEBUG(" Found my Listen Channel %d \n", listen_channel); ++ return listen_channel; ++ } ++ } ++ pos += 3 + attr_len; ++ } ++ return 0; ++} ++ ++static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request) ++{ ++ u32 n_ssids; ++ u32 n_channels; ++ u16 channel; ++ chanspec_t chanspec; ++ s32 i = 0, j = 0, offset; ++ char *ptr; ++ wlc_ssid_t ssid; ++ struct wl_priv *wl = wlcfg_drv_priv; ++ ++ memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); ++ params->bss_type = DOT11_BSSTYPE_ANY; ++ params->scan_type = 0; ++ params->nprobes = -1; ++ params->active_time = -1; ++ params->passive_time = -1; ++ params->home_time = -1; ++ params->channel_num = 0; ++ memset(¶ms->ssid, 0, sizeof(wlc_ssid_t)); ++ ++ AP6211_DEBUG("Preparing Scan request\n"); ++ AP6211_DEBUG("nprobes=%d\n", params->nprobes); ++ AP6211_DEBUG("active_time=%d\n", params->active_time); ++ AP6211_DEBUG("passive_time=%d\n", params->passive_time); ++ AP6211_DEBUG("home_time=%d\n", params->home_time); ++ AP6211_DEBUG("scan_type=%d\n", params->scan_type); ++ ++ params->nprobes = htod32(params->nprobes); ++ params->active_time = htod32(params->active_time); ++ params->passive_time = htod32(params->passive_time); ++ params->home_time = htod32(params->home_time); ++ ++ /* if request is null just exit so it will be all channel broadcast scan */ ++ if (!request) ++ return; ++ ++ n_ssids = request->n_ssids; ++ n_channels = request->n_channels; ++ ++ /* Copy channel array if applicable */ ++ AP6211_DEBUG("### List of channelspecs to scan ###\n"); ++ if (n_channels > 0) { ++ for (i = 0; i < n_channels; i++) { ++ chanspec = 0; ++ channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq); ++ /* SKIP DFS channels for Secondary interface */ ++ if ((wl->escan_info.ndev != wl_to_prmry_ndev(wl)) && ++ (request->channels[i]->flags & ++ (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN))) ++ continue; ++ ++ if (request->channels[i]->band == IEEE80211_BAND_2GHZ) { ++#ifdef WL_HOST_BAND_MGMT ++ if (wl->curr_band == WLC_BAND_5G) { ++ AP6211_DEBUG("In 5G only mode, omit 2G channel:%d\n", channel); ++ continue; ++ } ++#endif /* WL_HOST_BAND_MGMT */ ++ chanspec |= WL_CHANSPEC_BAND_2G; ++ } else { ++#ifdef WL_HOST_BAND_MGMT ++ if (wl->curr_band == WLC_BAND_2G) { ++ AP6211_DEBUG("In 2G only mode, omit 5G channel:%d\n", channel); ++ continue; ++ } ++#endif /* WL_HOST_BAND_MGMT */ ++ chanspec |= WL_CHANSPEC_BAND_5G; ++ } ++ ++ chanspec |= WL_CHANSPEC_BW_20; ++ chanspec |= WL_CHANSPEC_CTL_SB_NONE; ++ ++ params->channel_list[j] = channel; ++ params->channel_list[j] &= WL_CHANSPEC_CHAN_MASK; ++ params->channel_list[j] |= chanspec; ++ AP6211_DEBUG("Chan : %d, Channel spec: %x \n", ++ channel, params->channel_list[j]); ++ params->channel_list[j] = wl_chspec_host_to_driver(params->channel_list[j]); ++ j++; ++ } ++ } else { ++ AP6211_DEBUG("Scanning all channels\n"); ++ } ++ n_channels = j; ++ /* Copy ssid array if applicable */ ++ AP6211_DEBUG("### List of SSIDs to scan ###\n"); ++ if (n_ssids > 0) { ++ offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16); ++ offset = roundup(offset, sizeof(u32)); ++ ptr = (char*)params + offset; ++ for (i = 0; i < n_ssids; i++) { ++ memset(&ssid, 0, sizeof(wlc_ssid_t)); ++ ssid.SSID_len = request->ssids[i].ssid_len; ++ memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len); ++ if (!ssid.SSID_len) ++ AP6211_DEBUG("%d: Broadcast scan\n", i); ++ else ++ AP6211_DEBUG("%d: scan for %s size =%d\n", i, ++ ssid.SSID, ssid.SSID_len); ++ memcpy(ptr, &ssid, sizeof(wlc_ssid_t)); ++ ptr += sizeof(wlc_ssid_t); ++ } ++ } else { ++ AP6211_DEBUG("Broadcast scan\n"); ++ } ++ /* Adding mask to channel numbers */ ++ params->channel_num = ++ htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) | ++ (n_channels & WL_SCAN_PARAMS_COUNT_MASK)); ++ ++ if (n_channels == 1 && wl_get_drv_status_all(wl, CONNECTED)) { ++ params->active_time = WL_SCAN_CONNECT_DWELL_TIME_MS; ++ } ++} ++ ++static s32 ++wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, u16 action) ++{ ++ u32 n_channels; ++ u32 n_ssids; ++ s32 params_size = ++ (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params)); ++ struct wl_iscan_params *params = NULL; ++ s32 err = 0; ++ ++ if (request != NULL) { ++ n_channels = request->n_channels; ++ n_ssids = request->n_ssids; ++ /* Allocate space for populating ssids in wl_iscan_params struct */ ++ if (n_channels % 2) ++ /* If n_channels is odd, add a padd of u16 */ ++ params_size += sizeof(u16) * (n_channels + 1); ++ else ++ params_size += sizeof(u16) * n_channels; ++ ++ /* Allocate space for populating ssids in wl_iscan_params struct */ ++ params_size += sizeof(struct wlc_ssid) * n_ssids; ++ } ++ params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL); ++ if (!params) { ++ err = -ENOMEM; ++ goto done; ++ } ++ wl_scan_prep(¶ms->params, request); ++ ++ params->version = htod32(ISCAN_REQ_VERSION); ++ params->action = htod16(action); ++ params->scan_duration = htod16(0); ++ ++ if (params_size + sizeof("iscan") >= WLC_IOCTL_MEDLEN) { ++ AP6211_ERR("ioctl buffer length is not sufficient\n"); ++ err = -ENOMEM; ++ goto done; ++ } ++ err = wldev_iovar_setbuf(iscan->dev, "iscan", params, params_size, ++ iscan->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); ++ if (unlikely(err)) { ++ if (err == -EBUSY) { ++ AP6211_ERR("system busy : iscan canceled\n"); ++ } else { ++ AP6211_ERR("error (%d)\n", err); ++ } ++ } ++ ++done: ++ if (params) ++ kfree(params); ++ return err; ++} ++ ++static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request) ++{ ++ struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ s32 passive_scan; ++ s32 err = 0; ++ ++ iscan->state = WL_ISCAN_STATE_SCANING; ++ ++ passive_scan = wl->active_scan ? 0 : 1; ++ err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, ++ &passive_scan, sizeof(passive_scan), true); ++ if (unlikely(err)) { ++ AP6211_DEBUG("error (%d)\n", err); ++ return err; ++ } ++ wl->iscan_kickstart = true; ++ wl_run_iscan(iscan, request, WL_SCAN_ACTION_START); ++ mod_timer(&iscan->timer, jiffies + msecs_to_jiffies(iscan->timer_ms)); ++ iscan->timer_on = 1; ++ ++ return err; ++} ++ ++static s32 ++wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size) ++{ ++ wl_uint32_list_t *list; ++ s32 err = BCME_OK; ++ if (valid_chan_list == NULL || size <= 0) ++ return -ENOMEM; ++ ++ memset(valid_chan_list, 0, size); ++ list = (wl_uint32_list_t *)(void *) valid_chan_list; ++ list->count = htod32(WL_NUMCHANNELS); ++ err = wldev_ioctl(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size, false); ++ if (err != 0) { ++ AP6211_ERR("get channels failed with %d\n", err); ++ } ++ ++ return err; ++} ++ ++static s32 ++wl_run_escan(struct wl_priv *wl, struct net_device *ndev, ++ struct cfg80211_scan_request *request, uint16 action) ++{ ++ s32 err = BCME_OK; ++ u32 n_channels; ++ u32 n_ssids; ++ s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)); ++ wl_escan_params_t *params = NULL; ++ u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)]; ++ u32 num_chans = 0; ++ s32 channel; ++ s32 n_valid_chan; ++ s32 search_state = WL_P2P_DISC_ST_SCAN; ++ u32 i, j, n_nodfs = 0; ++ u16 *default_chan_list = NULL; ++ wl_uint32_list_t *list; ++ struct net_device *dev = NULL; ++ ++ AP6211_DEBUG("Enter \n"); ++ ++ if (!wl) { ++ err = -EINVAL; ++ goto exit; ++ } ++ if (!wl->p2p_supported || !p2p_scan(wl)) { ++ /* LEGACY SCAN TRIGGER */ ++ AP6211_DEBUG(" LEGACY E-SCAN START\n"); ++ ++ /* if scan request is not empty parse scan request paramters */ ++ if (request != NULL) { ++ n_channels = request->n_channels; ++ n_ssids = request->n_ssids; ++ /* Allocate space for populating ssids in wl_iscan_params struct */ ++ if (n_channels % 2) ++ /* If n_channels is odd, add a padd of u16 */ ++ params_size += sizeof(u16) * (n_channels + 1); ++ else ++ params_size += sizeof(u16) * n_channels; ++ ++ /* Allocate space for populating ssids in wl_iscan_params struct */ ++ params_size += sizeof(struct wlc_ssid) * n_ssids; ++ } ++ params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL); ++ if (params == NULL) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ wl_scan_prep(¶ms->params, request); ++ ++ params->version = htod32(ESCAN_REQ_VERSION); ++ params->action = htod16(action); ++ params->sync_id = htod16(0x1234); ++ if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) { ++ AP6211_ERR("ioctl buffer length not sufficient\n"); ++ kfree(params); ++ err = -ENOMEM; ++ goto exit; ++ } ++ err = wldev_iovar_setbuf(ndev, "escan", params, params_size, ++ wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL); ++ if (unlikely(err)) { ++ if (err == BCME_EPERM) ++ /* Scan Not permitted at this point of time */ ++ AP6211_DEBUG(" Escan not permitted at this time (%d)\n", err); ++ else ++ AP6211_ERR(" Escan set error (%d)\n", err); ++ } ++ kfree(params); ++ } ++ else if (p2p_is_on(wl) && p2p_scan(wl)) { ++ /* P2P SCAN TRIGGER */ ++ s32 _freq = 0; ++ n_nodfs = 0; ++ if (request && request->n_channels) { ++ num_chans = request->n_channels; ++ AP6211_DEBUG(" chann number : %d\n", num_chans); ++ default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list), ++ GFP_KERNEL); ++ if (default_chan_list == NULL) { ++ AP6211_ERR("channel list allocation failed \n"); ++ err = -ENOMEM; ++ goto exit; ++ } ++ if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) { ++ list = (wl_uint32_list_t *) chan_buf; ++ n_valid_chan = dtoh32(list->count); ++ for (i = 0; i < num_chans; i++) ++ { ++#ifdef WL_HOST_BAND_MGMT ++ int channel_band = 0; ++#endif /* WL_HOST_BAND_MGMT */ ++ _freq = request->channels[i]->center_freq; ++ channel = ieee80211_frequency_to_channel(_freq); ++#ifdef WL_HOST_BAND_MGMT ++ channel_band = (channel > CH_MAX_2G_CHANNEL) ? ++ WLC_BAND_5G : WLC_BAND_2G; ++ if ((wl->curr_band != WLC_BAND_AUTO) && ++ (wl->curr_band != channel_band) && ++ !IS_P2P_SOCIAL_CHANNEL(channel)) ++ continue; ++#endif /* WL_HOST_BAND_MGMT */ ++ ++ /* ignore DFS channels */ ++ if (request->channels[i]->flags & ++ (IEEE80211_CHAN_RADAR ++ | IEEE80211_CHAN_PASSIVE_SCAN)) ++ continue; ++ ++ for (j = 0; j < n_valid_chan; j++) { ++ /* allows only supported channel on ++ * current reguatory ++ */ ++ if (channel == (dtoh32(list->element[j]))) ++ default_chan_list[n_nodfs++] = ++ channel; ++ } ++ ++ } ++ } ++ if (num_chans == 3 && ( ++ (default_chan_list[0] == SOCIAL_CHAN_1) && ++ (default_chan_list[1] == SOCIAL_CHAN_2) && ++ (default_chan_list[2] == SOCIAL_CHAN_3))) { ++ /* SOCIAL CHANNELS 1, 6, 11 */ ++ search_state = WL_P2P_DISC_ST_SEARCH; ++ AP6211_DEBUG("P2P SEARCH PHASE START \n"); ++ } else if ((dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)) && ++ (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP)) { ++ /* If you are already a GO, then do SEARCH only */ ++ AP6211_DEBUG("Already a GO. Do SEARCH Only"); ++ search_state = WL_P2P_DISC_ST_SEARCH; ++ num_chans = n_nodfs; ++ ++ } else { ++ AP6211_DEBUG("P2P SCAN STATE START \n"); ++ num_chans = n_nodfs; ++ } ++ ++ } ++ err = wl_cfgp2p_escan(wl, ndev, wl->active_scan, num_chans, default_chan_list, ++ search_state, action, ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); ++ kfree(default_chan_list); ++ } ++exit: ++ if (unlikely(err)) { ++ /* Don't print Error incase of Scan suppress */ ++ if ((err == BCME_EPERM) && wl->scan_suppressed) ++ AP6211_DEBUG("Escan failed: Scan Suppressed \n"); ++ else ++ AP6211_ERR("error (%d)\n", err); ++ } ++ return err; ++} ++ ++ ++static s32 ++wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_scan_request *request) ++{ ++ s32 err = BCME_OK; ++ s32 passive_scan; ++ wl_scan_results_t *results; ++ AP6211_DEBUG("Enter \n"); ++ mutex_lock(&wl->usr_sync); ++ results = (wl_scan_results_t *) wl->escan_info.escan_buf; ++ results->version = 0; ++ results->count = 0; ++ results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; ++ ++ wl->escan_info.ndev = ndev; ++ wl->escan_info.wiphy = wiphy; ++ wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING; ++ passive_scan = wl->active_scan ? 0 : 1; ++ err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, ++ &passive_scan, sizeof(passive_scan), true); ++ if (unlikely(err)) { ++ AP6211_ERR("error (%d)\n", err); ++ goto exit; ++ } ++ ++ err = wl_run_escan(wl, ndev, request, WL_SCAN_ACTION_START); ++exit: ++ mutex_unlock(&wl->usr_sync); ++ return err; ++} ++ ++static s32 ++__wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_scan_request *request, ++ struct cfg80211_ssid *this_ssid) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct cfg80211_ssid *ssids; ++ struct wl_scan_req *sr = wl_to_sr(wl); ++ struct ether_addr primary_mac; ++ s32 passive_scan; ++ bool iscan_req; ++ bool escan_req = false; ++ bool p2p_ssid; ++#ifdef WL11U ++ bcm_tlv_t *interworking_ie; ++ u32 ie_len; ++#endif ++ s32 err = 0; ++ s32 bssidx = -1; ++ s32 i; ++ ++ unsigned long flags; ++ static s32 busy_count = 0; ++ ++ /* If scan req comes for p2p0, send it over primary I/F ++ * Scan results will be delivered corresponding to cfg80211_scan_request ++ */ ++ if (ndev == wl->p2p_net) { ++ ndev = wl_to_prmry_ndev(wl); ++ } ++ ++ if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(wl)) { ++ AP6211_ERR("Sending Action Frames. Try it again.\n"); ++ return -EAGAIN; ++ } ++ ++ AP6211_DEBUG("Enter wiphy (%p)\n", wiphy); ++ if (wl_get_drv_status_all(wl, SCANNING)) { ++ if (wl->scan_request == NULL) { ++ wl_clr_drv_status_all(wl, SCANNING); ++ AP6211_DEBUG("<<<<<<<<<<>>>>>>>>>>\n"); ++ } else { ++ AP6211_ERR("Scanning already\n"); ++ return -EAGAIN; ++ } ++ } ++ if (wl_get_drv_status(wl, SCAN_ABORTING, ndev)) { ++ AP6211_ERR("Scanning being aborted\n"); ++ return -EAGAIN; ++ } ++ if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) { ++ AP6211_ERR("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"); ++ return -EOPNOTSUPP; ++ } ++#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ if (wl_get_drv_status_all(wl, REMAINING_ON_CHANNEL)) { ++ AP6211_DEBUG("Remain_on_channel bit is set, somehow it didn't get cleared\n"); ++ wl_notify_escan_complete(wl, ndev, true, true); ++ } ++#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ ++ /* Arm scan timeout timer */ ++ mod_timer(&wl->scan_timeout, jiffies + msecs_to_jiffies(WL_SCAN_TIMER_INTERVAL_MS)); ++ iscan_req = false; ++ if (request) { /* scan bss */ ++ ssids = request->ssids; ++ if (wl->iscan_on && (!ssids || !ssids->ssid_len || request->n_ssids != 1)) { ++ iscan_req = true; ++ } else if (wl->escan_on) { ++ escan_req = true; ++ p2p_ssid = false; ++ for (i = 0; i < request->n_ssids; i++) { ++ if (ssids[i].ssid_len && ++ IS_P2P_SSID(ssids[i].ssid, ssids[i].ssid_len)) { ++ p2p_ssid = true; ++ break; ++ } ++ } ++ if (p2p_ssid) { ++ if (wl->p2p_supported) { ++ /* p2p scan trigger */ ++ if (p2p_on(wl) == false) { ++ /* p2p on at the first time */ ++ p2p_on(wl) = true; ++ wl_cfgp2p_set_firm_p2p(wl); ++ get_primary_mac(wl, &primary_mac); ++ wl_cfgp2p_generate_bss_mac(&primary_mac, ++ &wl->p2p->dev_addr, &wl->p2p->int_addr); ++ } ++ wl_clr_p2p_status(wl, GO_NEG_PHASE); ++ AP6211_DEBUG("P2P: GO_NEG_PHASE status cleared \n"); ++ p2p_scan(wl) = true; ++ } ++ } else { ++ /* legacy scan trigger ++ * So, we have to disable p2p discovery if p2p discovery is on ++ */ ++ if (wl->p2p_supported) { ++ p2p_scan(wl) = false; ++ /* If Netdevice is not equals to primary and p2p is on ++ * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE. ++ */ ++ ++ if (p2p_scan(wl) == false) { ++ if (wl_get_p2p_status(wl, DISCOVERY_ON)) { ++ err = wl_cfgp2p_discover_enable_search(wl, ++ false); ++ if (unlikely(err)) { ++ goto scan_out; ++ } ++ ++ } ++ } ++ } ++ if (!wl->p2p_supported || !p2p_scan(wl)) { ++ bssidx = wl_cfgp2p_find_idx(wl, ndev); ++ ++#ifdef WL11U ++ if ((interworking_ie = wl_cfg80211_find_interworking_ie( ++ (u8 *)request->ie, request->ie_len)) != NULL) { ++ ie_len = interworking_ie->len; ++ ++ err = wl_cfg80211_add_iw_ie(wl, ndev, bssidx, ++ VNDR_IE_CUSTOM_FLAG, interworking_ie->id, ++ interworking_ie->data, interworking_ie->len); ++ ++ if (unlikely(err)) { ++ goto scan_out; ++ } ++ } else if (wl->iw_ie_len != 0) { ++ /* we have to clear IW IE and disable gratuitous APR */ ++ wl_cfg80211_add_iw_ie(wl, ndev, bssidx, ++ VNDR_IE_CUSTOM_FLAG, ++ DOT11_MNG_INTERWORKING_ID, ++ 0, 0); ++ ++ wldev_iovar_setint_bsscfg(ndev, "grat_arp", 0, ++ bssidx); ++ /* we don't care about error */ ++ } ++#endif /* WL11U */ ++ err = wl_cfgp2p_set_management_ie(wl, ndev, bssidx, ++ VNDR_IE_PRBREQ_FLAG, (u8 *)request->ie, ++ request->ie_len); ++ ++ if (unlikely(err)) { ++ goto scan_out; ++ } ++ ++ } ++ } ++ } ++ } else { /* scan in ibss */ ++ /* we don't do iscan in ibss */ ++ ssids = this_ssid; ++ } ++ wl->scan_request = request; ++ wl_set_drv_status(wl, SCANNING, ndev); ++ if (iscan_req) { ++ err = wl_do_iscan(wl, request); ++ if (likely(!err)) ++ goto scan_success; ++ else ++ goto scan_out; ++ } else if (escan_req) { ++ if (wl->p2p_supported) { ++ if (p2p_on(wl) && p2p_scan(wl)) { ++ ++ /* find my listen channel */ ++ wl->afx_hdl->my_listen_chan = ++ wl_find_listen_channel(wl, (u8 *)request->ie, ++ request->ie_len); ++ err = wl_cfgp2p_enable_discovery(wl, ndev, ++ request->ie, request->ie_len); ++ ++ if (unlikely(err)) { ++ goto scan_out; ++ } ++ } ++ } ++ err = wl_do_escan(wl, wiphy, ndev, request); ++ if (likely(!err)) ++ goto scan_success; ++ else ++ goto scan_out; ++ ++ ++ } else { ++ memset(&sr->ssid, 0, sizeof(sr->ssid)); ++ sr->ssid.SSID_len = ++ min_t(u8, sizeof(sr->ssid.SSID), ssids->ssid_len); ++ if (sr->ssid.SSID_len) { ++ memcpy(sr->ssid.SSID, ssids->ssid, sr->ssid.SSID_len); ++ sr->ssid.SSID_len = htod32(sr->ssid.SSID_len); ++ AP6211_DEBUG("Specific scan ssid=\"%s\" len=%d\n", ++ sr->ssid.SSID, sr->ssid.SSID_len); ++ } else { ++ AP6211_DEBUG("Broadcast scan\n"); ++ } ++ AP6211_DEBUG("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len); ++ passive_scan = wl->active_scan ? 0 : 1; ++ err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, ++ &passive_scan, sizeof(passive_scan), true); ++ if (unlikely(err)) { ++ AP6211_DEBUG("WLC_SET_PASSIVE_SCAN error (%d)\n", err); ++ goto scan_out; ++ } ++ err = wldev_ioctl(ndev, WLC_SCAN, &sr->ssid, ++ sizeof(sr->ssid), false); ++ if (err) { ++ if (err == -EBUSY) { ++ AP6211_ERR("system busy : scan for \"%s\" " ++ "canceled\n", sr->ssid.SSID); ++ } else { ++ AP6211_ERR("WLC_SCAN error (%d)\n", err); ++ } ++ goto scan_out; ++ } ++ } ++ ++scan_success: ++ ++ busy_count = 0; ++ ++ return 0; ++ ++scan_out: ++ ++ if (err == BCME_BUSY || err == BCME_NOTREADY) { ++ AP6211_ERR("Scan err = (%d), busy?%d", err, -EBUSY); ++ err = -EBUSY; ++ } ++ ++#define SCAN_EBUSY_RETRY_LIMIT 10 ++ if (err == -EBUSY) { ++ if (busy_count++ > SCAN_EBUSY_RETRY_LIMIT) { ++ struct ether_addr bssid; ++ s32 ret = 0; ++ busy_count = 0; ++ AP6211_ERR("Unusual continuous EBUSY error, %d %d %d %d %d %d %d %d %d\n", ++ wl_get_drv_status(wl, SCANNING, ndev), ++ wl_get_drv_status(wl, SCAN_ABORTING, ndev), ++ wl_get_drv_status(wl, CONNECTING, ndev), ++ wl_get_drv_status(wl, CONNECTED, ndev), ++ wl_get_drv_status(wl, DISCONNECTING, ndev), ++ wl_get_drv_status(wl, AP_CREATING, ndev), ++ wl_get_drv_status(wl, AP_CREATED, ndev), ++ wl_get_drv_status(wl, SENDING_ACT_FRM, ndev), ++ wl_get_drv_status(wl, SENDING_ACT_FRM, ndev)); ++ ++ bzero(&bssid, sizeof(bssid)); ++ if ((ret = wldev_ioctl(ndev, WLC_GET_BSSID, ++ &bssid, ETHER_ADDR_LEN, false)) == 0) ++ AP6211_ERR("FW is connected with " MACDBG "/n", ++ MAC2STRDBG(bssid.octet)); ++ else ++ AP6211_ERR("GET BSSID failed with %d\n", ret); ++ ++ wl_cfg80211_disconnect(wiphy, ndev, DOT11_RC_DISASSOC_LEAVING); ++ } ++ } else { ++ busy_count = 0; ++ } ++ wl_clr_drv_status(wl, SCANNING, ndev); ++ if (timer_pending(&wl->scan_timeout)) ++ del_timer_sync(&wl->scan_timeout); ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ wl->scan_request = NULL; ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ return err; ++} ++ ++static s32 ++wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_scan_request *request) ++{ ++ s32 err = 0; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ ++ AP6211_DEBUG("Enter \n"); ++ CHECK_SYS_UP(wl); ++ ++ err = __wl_cfg80211_scan(wiphy, ndev, request, NULL); ++ if (unlikely(err)) { ++ if ((err == BCME_EPERM) && wl->scan_suppressed) ++ AP6211_DEBUG("scan not permitted at this time (%d)\n", err); ++ else ++ AP6211_ERR("scan error (%d)\n", err); ++ return err; ++ } ++ ++ return err; ++} ++ ++static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold) ++{ ++ s32 err = 0; ++ ++ err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold); ++ if (unlikely(err)) { ++ AP6211_ERR("Error (%d)\n", err); ++ return err; ++ } ++ return err; ++} ++ ++static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold) ++{ ++ s32 err = 0; ++ ++ err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0); ++ if (unlikely(err)) { ++ AP6211_ERR("Error (%d)\n", err); ++ return err; ++ } ++ return err; ++} ++ ++static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l) ++{ ++ s32 err = 0; ++ u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL); ++ ++ retry = htod32(retry); ++ err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), true); ++ if (unlikely(err)) { ++ AP6211_ERR("cmd (%d) , error (%d)\n", cmd, err); ++ return err; ++ } ++ return err; ++} ++ ++static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) ++{ ++ struct wl_priv *wl = (struct wl_priv *)wiphy_priv(wiphy); ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ s32 err = 0; ++ ++ CHECK_SYS_UP(wl); ++ AP6211_DEBUG("Enter\n"); ++ if (changed & WIPHY_PARAM_RTS_THRESHOLD && ++ (wl->conf->rts_threshold != wiphy->rts_threshold)) { ++ wl->conf->rts_threshold = wiphy->rts_threshold; ++ err = wl_set_rts(ndev, wl->conf->rts_threshold); ++ if (!err) ++ return err; ++ } ++ if (changed & WIPHY_PARAM_FRAG_THRESHOLD && ++ (wl->conf->frag_threshold != wiphy->frag_threshold)) { ++ wl->conf->frag_threshold = wiphy->frag_threshold; ++ err = wl_set_frag(ndev, wl->conf->frag_threshold); ++ if (!err) ++ return err; ++ } ++ if (changed & WIPHY_PARAM_RETRY_LONG && ++ (wl->conf->retry_long != wiphy->retry_long)) { ++ wl->conf->retry_long = wiphy->retry_long; ++ err = wl_set_retry(ndev, wl->conf->retry_long, true); ++ if (!err) ++ return err; ++ } ++ if (changed & WIPHY_PARAM_RETRY_SHORT && ++ (wl->conf->retry_short != wiphy->retry_short)) { ++ wl->conf->retry_short = wiphy->retry_short; ++ err = wl_set_retry(ndev, wl->conf->retry_short, false); ++ if (!err) { ++ return err; ++ } ++ } ++ ++ return err; ++} ++ ++static s32 ++wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_ibss_params *params) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct cfg80211_bss *bss; ++ struct ieee80211_channel *chan; ++ struct wl_join_params join_params; ++ struct cfg80211_ssid ssid; ++ s32 scan_retry = 0; ++ s32 err = 0; ++ bool rollback_lock = false; ++ ++ AP6211_DEBUG("In\n"); ++ CHECK_SYS_UP(wl); ++ if (params->bssid) { ++ AP6211_ERR("Invalid bssid\n"); ++ return -EOPNOTSUPP; ++ } ++ bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len); ++ if (!bss) { ++ memcpy(ssid.ssid, params->ssid, params->ssid_len); ++ ssid.ssid_len = params->ssid_len; ++ do { ++ if (unlikely ++ (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) == ++ -EBUSY)) { ++ wl_delay(150); ++ } else { ++ break; ++ } ++ } while (++scan_retry < WL_SCAN_RETRY_MAX); ++ /* to allow scan_inform to propagate to cfg80211 plane */ ++ if (rtnl_is_locked()) { ++ rtnl_unlock(); ++ rollback_lock = true; ++ } ++ ++ /* wait 4 secons till scan done.... */ ++ schedule_timeout_interruptible(msecs_to_jiffies(4000)); ++ if (rollback_lock) ++ rtnl_lock(); ++ bss = cfg80211_get_ibss(wiphy, NULL, ++ params->ssid, params->ssid_len); ++ } ++ if (bss) { ++ wl->ibss_starter = false; ++ AP6211_DEBUG("Found IBSS\n"); ++ } else { ++ wl->ibss_starter = true; ++ } ++ chan = params->channel; ++ if (chan) ++ wl->channel = ieee80211_frequency_to_channel(chan->center_freq); ++ /* ++ * Join with specific BSSID and cached SSID ++ * If SSID is zero join based on BSSID only ++ */ ++ memset(&join_params, 0, sizeof(join_params)); ++ memcpy((void *)join_params.ssid.SSID, (void *)params->ssid, ++ params->ssid_len); ++ join_params.ssid.SSID_len = htod32(params->ssid_len); ++ if (params->bssid) ++ memcpy(&join_params.params.bssid, params->bssid, ++ ETHER_ADDR_LEN); ++ else ++ memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN); ++ ++ err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, ++ sizeof(join_params), true); ++ if (unlikely(err)) { ++ AP6211_ERR("Error (%d)\n", err); ++ return err; ++ } ++ return err; ++} ++ ++static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ s32 err = 0; ++ ++ CHECK_SYS_UP(wl); ++ wl_link_down(wl); ++ ++ return err; ++} ++ ++static s32 ++wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct wl_security *sec; ++ s32 val = 0; ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) ++ val = WPA_AUTH_PSK | ++ WPA_AUTH_UNSPECIFIED; ++ else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) ++ val = WPA2_AUTH_PSK| ++ WPA2_AUTH_UNSPECIFIED; ++ else ++ val = WPA_AUTH_DISABLED; ++ ++ if (is_wps_conn(sme)) ++ val = WPA_AUTH_DISABLED; ++ ++#ifdef BCMWAPI_WPI ++ if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { ++ AP6211_DEBUG(" * wl_set_wpa_version, set wpa_auth" ++ " to WPA_AUTH_WAPI 0x400"); ++ val = WAPI_AUTH_PSK; /* | WAPI_AUTH_UNSPECIFIED; */ ++ } ++#endif ++ AP6211_DEBUG("setting wpa_auth to 0x%0x\n", val); ++ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); ++ if (unlikely(err)) { ++ AP6211_ERR("set wpa_auth failed (%d)\n", err); ++ return err; ++ } ++ sec = wl_read_prof(wl, dev, WL_PROF_SEC); ++ sec->wpa_versions = sme->crypto.wpa_versions; ++ return err; ++} ++ ++#ifdef BCMWAPI_WPI ++static s32 ++wl_set_set_wapi_ie(struct net_device *dev, struct cfg80211_connect_params *sme) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ AP6211_DEBUG(" %s \n", __FUNCTION__); ++ ++ if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { ++ err = wldev_iovar_setbuf_bsscfg(dev, "wapiie", sme->ie, ++ sme->ie_len, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ if (unlikely(err)) { ++ AP6211_ERR("===> set_wapi_ie Error (%d)\n", err); ++ return err; ++ } ++ } else ++ AP6211_DEBUG(" * skip \n"); ++ return err; ++} ++#endif /* BCMWAPI_WPI */ ++ ++static s32 ++wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct wl_security *sec; ++ s32 val = 0; ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ switch (sme->auth_type) { ++ case NL80211_AUTHTYPE_OPEN_SYSTEM: ++ val = WL_AUTH_OPEN_SYSTEM; ++ AP6211_DEBUG("open system\n"); ++ break; ++ case NL80211_AUTHTYPE_SHARED_KEY: ++ val = WL_AUTH_SHARED_KEY; ++ AP6211_DEBUG("shared key\n"); ++ break; ++ case NL80211_AUTHTYPE_AUTOMATIC: ++ val = WL_AUTH_OPEN_SHARED; ++ AP6211_DEBUG("automatic\n"); ++ break; ++ default: ++ val = WL_AUTH_OPEN_SHARED; ++ AP6211_ERR("invalid auth type (%d)\n", sme->auth_type); ++ break; ++ } ++ ++ err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); ++ if (unlikely(err)) { ++ AP6211_ERR("set auth failed (%d)\n", err); ++ return err; ++ } ++ sec = wl_read_prof(wl, dev, WL_PROF_SEC); ++ sec->auth_type = sme->auth_type; ++ return err; ++} ++ ++static s32 ++wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct wl_security *sec; ++ s32 pval = 0; ++ s32 gval = 0; ++ s32 err = 0; ++#ifdef BCMWAPI_WPI ++ s32 val = 0; ++#endif ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ if (sme->crypto.n_ciphers_pairwise) { ++ switch (sme->crypto.ciphers_pairwise[0]) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ case WLAN_CIPHER_SUITE_WEP104: ++ pval = WEP_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ pval = TKIP_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ pval = AES_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ pval = AES_ENABLED; ++ break; ++#ifdef BCMWAPI_WPI ++ case WLAN_CIPHER_SUITE_SMS4: ++ val = SMS4_ENABLED; ++ pval = SMS4_ENABLED; ++ break; ++#endif ++ default: ++ AP6211_ERR("invalid cipher pairwise (%d)\n", ++ sme->crypto.ciphers_pairwise[0]); ++ return -EINVAL; ++ } ++ } ++ if (sme->crypto.cipher_group) { ++ switch (sme->crypto.cipher_group) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ case WLAN_CIPHER_SUITE_WEP104: ++ gval = WEP_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ gval = TKIP_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ gval = AES_ENABLED; ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ gval = AES_ENABLED; ++ break; ++#ifdef BCMWAPI_WPI ++ case WLAN_CIPHER_SUITE_SMS4: ++ val = SMS4_ENABLED; ++ gval = SMS4_ENABLED; ++ break; ++#endif ++ default: ++ AP6211_ERR("invalid cipher group (%d)\n", ++ sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } ++ ++ AP6211_DEBUG("pval (%d) gval (%d)\n", pval, gval); ++ ++ if (is_wps_conn(sme)) { ++ if (sme->privacy) ++ err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); ++#ifdef BCMWAPI_WPI ++ else if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) { ++ AP6211_DEBUG(" NO, is_wps_conn, WAPI set to SMS4_ENABLED"); ++ err = wldev_iovar_setint_bsscfg(dev, "wsec", val, bssidx); ++ } ++#endif ++ else ++ /* WPS-2.0 allows no security */ ++ err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); ++ } else { ++ AP6211_DEBUG(" NO, is_wps_conn, Set pval | gval to WSEC"); ++ err = wldev_iovar_setint_bsscfg(dev, "wsec", ++ pval | gval, bssidx); ++ } ++ if (unlikely(err)) { ++ AP6211_ERR("error (%d)\n", err); ++ return err; ++ } ++ ++ sec = wl_read_prof(wl, dev, WL_PROF_SEC); ++ sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0]; ++ sec->cipher_group = sme->crypto.cipher_group; ++ ++ return err; ++} ++ ++static s32 ++wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct wl_security *sec; ++ s32 val = 0; ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ if (sme->crypto.n_akm_suites) { ++ err = wldev_iovar_getint(dev, "wpa_auth", &val); ++ if (unlikely(err)) { ++ AP6211_ERR("could not get wpa_auth (%d)\n", err); ++ return err; ++ } ++ if (val & (WPA_AUTH_PSK | ++ WPA_AUTH_UNSPECIFIED)) { ++ switch (sme->crypto.akm_suites[0]) { ++ case WLAN_AKM_SUITE_8021X: ++ val = WPA_AUTH_UNSPECIFIED; ++ break; ++ case WLAN_AKM_SUITE_PSK: ++ val = WPA_AUTH_PSK; ++ break; ++ default: ++ AP6211_ERR("invalid cipher group (%d)\n", ++ sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } else if (val & (WPA2_AUTH_PSK | ++ WPA2_AUTH_UNSPECIFIED)) { ++ switch (sme->crypto.akm_suites[0]) { ++ case WLAN_AKM_SUITE_8021X: ++ val = WPA2_AUTH_UNSPECIFIED; ++ break; ++ case WLAN_AKM_SUITE_PSK: ++ val = WPA2_AUTH_PSK; ++ break; ++ default: ++ AP6211_ERR("invalid cipher group (%d)\n", ++ sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } ++#ifdef BCMWAPI_WPI ++ else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) { ++ switch (sme->crypto.akm_suites[0]) { ++ case WLAN_AKM_SUITE_WAPI_CERT: ++ val = WAPI_AUTH_UNSPECIFIED; ++ break; ++ case WLAN_AKM_SUITE_WAPI_PSK: ++ val = WAPI_AUTH_PSK; ++ break; ++ default: ++ AP6211_ERR("invalid cipher group (%d)\n", ++ sme->crypto.cipher_group); ++ return -EINVAL; ++ } ++ } ++#endif ++ AP6211_DEBUG("setting wpa_auth to %d\n", val); ++ ++ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); ++ if (unlikely(err)) { ++ AP6211_ERR("could not set wpa_auth (%d)\n", err); ++ return err; ++ } ++ } ++ sec = wl_read_prof(wl, dev, WL_PROF_SEC); ++ sec->wpa_auth = sme->crypto.akm_suites[0]; ++ ++ return err; ++} ++ ++static s32 ++wl_set_set_sharedkey(struct net_device *dev, ++ struct cfg80211_connect_params *sme) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct wl_security *sec; ++ struct wl_wsec_key key; ++ s32 val; ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ AP6211_DEBUG("key len (%d)\n", sme->key_len); ++ if (sme->key_len) { ++ sec = wl_read_prof(wl, dev, WL_PROF_SEC); ++ AP6211_DEBUG("wpa_versions 0x%x cipher_pairwise 0x%x\n", ++ sec->wpa_versions, sec->cipher_pairwise); ++ if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 | ++ NL80211_WPA_VERSION_2 ++#ifdef BCMWAPI_WPI ++ | NL80211_WAPI_VERSION_1 ++#endif ++ )) && ++ (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 | ++ WLAN_CIPHER_SUITE_WEP104 ++#ifdef BCMWAPI_WPI ++ | WLAN_CIPHER_SUITE_SMS4 ++#endif ++ ))) ++ { ++ memset(&key, 0, sizeof(key)); ++ key.len = (u32) sme->key_len; ++ key.index = (u32) sme->key_idx; ++ if (unlikely(key.len > sizeof(key.data))) { ++ AP6211_ERR("Too long key length (%u)\n", key.len); ++ return -EINVAL; ++ } ++ memcpy(key.data, sme->key, key.len); ++ key.flags = WL_PRIMARY_KEY; ++ switch (sec->cipher_pairwise) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ key.algo = CRYPTO_ALGO_WEP1; ++ break; ++ case WLAN_CIPHER_SUITE_WEP104: ++ key.algo = CRYPTO_ALGO_WEP128; ++ break; ++#ifdef BCMWAPI_WPI ++ case WLAN_CIPHER_SUITE_SMS4: ++ key.algo = CRYPTO_ALGO_SMS4; ++ break; ++#endif ++ default: ++ AP6211_ERR("Invalid algorithm (%d)\n", ++ sme->crypto.ciphers_pairwise[0]); ++ return -EINVAL; ++ } ++ /* Set the new key/index */ ++ AP6211_DEBUG("key length (%d) key index (%d) algo (%d)\n", ++ key.len, key.index, key.algo); ++ AP6211_DEBUG("key \"%s\"\n", key.data); ++ swap_key_from_BE(&key); ++ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_SET_KEY error (%d)\n", err); ++ return err; ++ } ++ if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { ++ AP6211_DEBUG("set auth_type to shared key\n"); ++ val = WL_AUTH_SHARED_KEY; /* shared key */ ++ err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); ++ if (unlikely(err)) { ++ AP6211_ERR("set auth failed (%d)\n", err); ++ return err; ++ } ++ } ++ } ++ } ++ return err; ++} ++ ++#ifdef ESCAN_RESULT_PATCH ++static u8 connect_req_bssid[6]; ++static u8 broad_bssid[6]; ++#endif ++ ++ ++static s32 ++wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_connect_params *sme) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct ieee80211_channel *chan = sme->channel; ++ wl_extjoin_params_t *ext_join_params; ++ struct wl_join_params join_params; ++ size_t join_params_size; ++ s32 err = 0; ++ wpa_ie_fixed_t *wpa_ie; ++ bcm_tlv_t *wpa2_ie; ++ u8* wpaie = 0; ++ u32 wpaie_len = 0; ++ u32 chan_cnt = 0; ++ struct ether_addr bssid; ++ int ret; ++ ++ AP6211_DEBUG("In\n"); ++ ++ if (unlikely(!sme->ssid)) { ++ AP6211_ERR("Invalid ssid\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ CHECK_SYS_UP(wl); ++ ++ /* ++ * Cancel ongoing scan to sync up with sme state machine of cfg80211. ++ */ ++#if !defined(ESCAN_RESULT_PATCH) ++ if (wl->scan_request) { ++ wl_notify_escan_complete(wl, dev, true, true); ++ } ++#endif ++#ifdef ESCAN_RESULT_PATCH ++ if (sme->bssid) { ++ memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN); ++ } ++ else { ++ bzero(connect_req_bssid, ETHER_ADDR_LEN); ++ } ++ bzero(broad_bssid, ETHER_ADDR_LEN); ++#endif ++ ++ bzero(&bssid, sizeof(bssid)); ++ if (!wl_get_drv_status(wl, CONNECTED, dev)&& ++ (ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false)) == 0) { ++ if (!ETHER_ISNULLADDR(&bssid)) { ++ scb_val_t scbval; ++ wl_set_drv_status(wl, DISCONNECTING, dev); ++ scbval.val = DOT11_RC_DISASSOC_LEAVING; ++ memcpy(&scbval.ea, &bssid, ETHER_ADDR_LEN); ++ scbval.val = htod32(scbval.val); ++ ++ AP6211_DEBUG("drv status CONNECTED is not set, but connected in FW!" MACDBG "\n", ++ MAC2STRDBG(bssid.octet)); ++ err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, ++ sizeof(scb_val_t), true); ++ if (unlikely(err)) { ++ wl_clr_drv_status(wl, DISCONNECTING, dev); ++ AP6211_ERR("error (%d)\n", err); ++ return err; ++ } ++ while (wl_get_drv_status(wl, DISCONNECTING, dev)) { ++ AP6211_ERR("Waiting for disconnection terminated.\n"); ++ msleep(20); ++ } ++ } else ++ AP6211_DEBUG("Currently not associated!\n"); ++ } ++ ++ /* Clean BSSID */ ++ bzero(&bssid, sizeof(bssid)); ++ if (!wl_get_drv_status(wl, DISCONNECTING, dev)) ++ wl_update_prof(wl, dev, NULL, (void *)&bssid, WL_PROF_BSSID); ++ ++ if (p2p_is_on(wl) && (dev != wl_to_prmry_ndev(wl))) { ++ /* we only allow to connect using virtual interface in case of P2P */ ++ wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), ++ VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); ++ } else if (dev == wl_to_prmry_ndev(wl)) { ++ /* find the RSN_IE */ ++ if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len, ++ DOT11_MNG_RSN_ID)) != NULL) { ++ AP6211_DEBUG(" WPA2 IE is found\n"); ++ } ++ /* find the WPA_IE */ ++ if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)sme->ie, ++ sme->ie_len)) != NULL) { ++ AP6211_DEBUG(" WPA IE is found\n"); ++ } ++ if (wpa_ie != NULL || wpa2_ie != NULL) { ++ wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie; ++ wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len; ++ wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN; ++ wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len, ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); ++ } else { ++ wldev_iovar_setbuf(dev, "wpaie", NULL, 0, ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); ++ } ++ ++ err = wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), ++ VNDR_IE_ASSOCREQ_FLAG, (u8 *)sme->ie, sme->ie_len); ++ if (unlikely(err)) { ++ return err; ++ } ++ } ++ ++ if (chan) { ++ wl->channel = ieee80211_frequency_to_channel(chan->center_freq); ++ chan_cnt = 1; ++ AP6211_DEBUG("channel (%d), center_req (%d), %d channels\n", wl->channel, ++ chan->center_freq, chan_cnt); ++ } else ++ wl->channel = 0; ++ ++#ifdef BCMWAPI_WPI ++ AP6211_DEBUG("1. enable wapi auth\n"); ++ if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { ++ AP6211_DEBUG("2. set wapi ie \n"); ++ err = wl_set_set_wapi_ie(dev, sme); ++ if (unlikely(err)) ++ return err; ++ } else ++ AP6211_DEBUG("2. Not wapi ie \n"); ++#endif ++ AP6211_DEBUG("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len); ++ AP6211_DEBUG("3. set wapi version \n"); ++ err = wl_set_wpa_version(dev, sme); ++ if (unlikely(err)) { ++ AP6211_ERR("Invalid wpa_version\n"); ++ return err; ++ } ++#ifdef BCMWAPI_WPI ++ if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) ++ AP6211_DEBUG("4. WAPI Dont Set wl_set_auth_type\n"); ++ else { ++ AP6211_DEBUG("4. wl_set_auth_type\n"); ++#endif ++ err = wl_set_auth_type(dev, sme); ++ if (unlikely(err)) { ++ AP6211_ERR("Invalid auth type\n"); ++ return err; ++ } ++#ifdef BCMWAPI_WPI ++ ++ } ++#endif ++ ++ err = wl_set_set_cipher(dev, sme); ++ if (unlikely(err)) { ++ AP6211_ERR("Invalid ciper\n"); ++ return err; ++ } ++ ++ err = wl_set_key_mgmt(dev, sme); ++ if (unlikely(err)) { ++ AP6211_ERR("Invalid key mgmt\n"); ++ return err; ++ } ++ ++ err = wl_set_set_sharedkey(dev, sme); ++ if (unlikely(err)) { ++ AP6211_ERR("Invalid shared key\n"); ++ return err; ++ } ++ ++ /* ++ * Join with specific BSSID and cached SSID ++ * If SSID is zero join based on BSSID only ++ */ ++ join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE + ++ chan_cnt * sizeof(chanspec_t); ++ ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL); ++ if (ext_join_params == NULL) { ++ err = -ENOMEM; ++ wl_clr_drv_status(wl, CONNECTING, dev); ++ goto exit; ++ } ++ ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len); ++ memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len); ++ wl_update_prof(wl, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID); ++ ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len); ++ /* increate dwell time to receive probe response or detect Beacon ++ * from target AP at a noisy air only during connect command ++ */ ++ ext_join_params->scan.active_time = WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS; ++ ext_join_params->scan.passive_time = WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS; ++ /* Set up join scan parameters */ ++ ext_join_params->scan.scan_type = -1; ++ ext_join_params->scan.nprobes ++ = (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS); ++ ext_join_params->scan.home_time = -1; ++ ++ if (sme->bssid) ++ memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN); ++ else ++ memcpy(&ext_join_params->assoc.bssid, ðer_bcast, ETH_ALEN); ++ ext_join_params->assoc.chanspec_num = chan_cnt; ++ if (chan_cnt) { ++ u16 channel, band, bw, ctl_sb; ++ chanspec_t chspec; ++ channel = wl->channel; ++ band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G ++ : WL_CHANSPEC_BAND_5G; ++ bw = WL_CHANSPEC_BW_20; ++ ctl_sb = WL_CHANSPEC_CTL_SB_NONE; ++ chspec = (channel | band | bw | ctl_sb); ++ ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; ++ ext_join_params->assoc.chanspec_list[0] |= chspec; ++ ext_join_params->assoc.chanspec_list[0] = ++ wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]); ++ } ++ ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num); ++ if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { ++ AP6211_DEBUG("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID, ++ ext_join_params->ssid.SSID_len); ++ } ++ wl_set_drv_status(wl, CONNECTING, dev); ++ err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, wl_cfgp2p_find_idx(wl, dev), &wl->ioctl_buf_sync); ++ kfree(ext_join_params); ++ if (err) { ++ wl_clr_drv_status(wl, CONNECTING, dev); ++ if (err == BCME_UNSUPPORTED) { ++ AP6211_DEBUG("join iovar is not supported\n"); ++ goto set_ssid; ++ } else ++ AP6211_ERR("error (%d)\n", err); ++ } else ++ goto exit; ++ ++set_ssid: ++ memset(&join_params, 0, sizeof(join_params)); ++ join_params_size = sizeof(join_params.ssid); ++ ++ join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len); ++ memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len); ++ join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); ++ wl_update_prof(wl, dev, NULL, &join_params.ssid, WL_PROF_SSID); ++ if (sme->bssid) ++ memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN); ++ else ++ memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN); ++ ++ wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size); ++ AP6211_DEBUG("join_param_size %d\n", join_params_size); ++ ++ if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { ++ AP6211_DEBUG("ssid \"%s\", len (%d)\n", join_params.ssid.SSID, ++ join_params.ssid.SSID_len); ++ } ++ wl_set_drv_status(wl, CONNECTING, dev); ++ err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true); ++ if (err) { ++ AP6211_ERR("error (%d)\n", err); ++ wl_clr_drv_status(wl, CONNECTING, dev); ++ } ++exit: ++ return err; ++} ++ ++static s32 ++wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, ++ u16 reason_code) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ scb_val_t scbval; ++ bool act = false; ++ s32 err = 0; ++ u8 *curbssid; ++ AP6211_ERR("Reason %d\n", reason_code); ++ CHECK_SYS_UP(wl); ++ act = *(bool *) wl_read_prof(wl, dev, WL_PROF_ACT); ++ curbssid = wl_read_prof(wl, dev, WL_PROF_BSSID); ++ if (act) { ++ /* ++ * Cancel ongoing scan to sync up with sme state machine of cfg80211. ++ */ ++#if !defined(ESCAN_RESULT_PATCH) ++ /* Let scan aborted by F/W */ ++ if (wl->scan_request) { ++ wl_notify_escan_complete(wl, dev, true, true); ++ } ++#endif /* ESCAN_RESULT_PATCH */ ++ wl_set_drv_status(wl, DISCONNECTING, dev); ++ scbval.val = reason_code; ++ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); ++ scbval.val = htod32(scbval.val); ++ err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, ++ sizeof(scb_val_t), true); ++ if (unlikely(err)) { ++ wl_clr_drv_status(wl, DISCONNECTING, dev); ++ AP6211_ERR("error (%d)\n", err); ++ return err; ++ } ++ } ++ ++ return err; ++} ++ ++static s32 ++wl_cfg80211_set_tx_power(struct wiphy *wiphy, ++ enum nl80211_tx_power_setting type, s32 dbm) ++{ ++ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ u16 txpwrmw; ++ s32 err = 0; ++ s32 disable = 0; ++ ++ CHECK_SYS_UP(wl); ++ switch (type) { ++ case NL80211_TX_POWER_AUTOMATIC: ++ break; ++ case NL80211_TX_POWER_LIMITED: ++ if (dbm < 0) { ++ AP6211_ERR("TX_POWER_LIMITTED - dbm is negative\n"); ++ return -EINVAL; ++ } ++ break; ++ case NL80211_TX_POWER_FIXED: ++ if (dbm < 0) { ++ AP6211_ERR("TX_POWER_FIXED - dbm is negative..\n"); ++ return -EINVAL; ++ } ++ break; ++ } ++ /* Make sure radio is off or on as far as software is concerned */ ++ disable = WL_RADIO_SW_DISABLE << 16; ++ disable = htod32(disable); ++ err = wldev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable), true); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_SET_RADIO error (%d)\n", err); ++ return err; ++ } ++ ++ if (dbm > 0xffff) ++ txpwrmw = 0xffff; ++ else ++ txpwrmw = (u16) dbm; ++ err = wldev_iovar_setint(ndev, "qtxpower", ++ (s32) (bcm_mw_to_qdbm(txpwrmw))); ++ if (unlikely(err)) { ++ AP6211_ERR("qtxpower error (%d)\n", err); ++ return err; ++ } ++ wl->conf->tx_power = dbm; ++ ++ return err; ++} ++ ++static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ s32 txpwrdbm; ++ u8 result; ++ s32 err = 0; ++ ++ CHECK_SYS_UP(wl); ++ err = wldev_iovar_getint(ndev, "qtxpower", &txpwrdbm); ++ if (unlikely(err)) { ++ AP6211_ERR("error (%d)\n", err); ++ return err; ++ } ++ result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE); ++ *dbm = (s32) bcm_qdbm_to_mw(result); ++ ++ return err; ++} ++ ++static s32 ++wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, bool unicast, bool multicast) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ u32 index; ++ s32 wsec; ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ AP6211_DEBUG("key index (%d)\n", key_idx); ++ CHECK_SYS_UP(wl); ++ err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_GET_WSEC error (%d)\n", err); ++ return err; ++ } ++ if (wsec & WEP_ENABLED) { ++ /* Just select a new current key */ ++ index = (u32) key_idx; ++ index = htod32(index); ++ err = wldev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index, ++ sizeof(index), true); ++ if (unlikely(err)) { ++ AP6211_ERR("error (%d)\n", err); ++ } ++ } ++ return err; ++} ++ ++static s32 ++wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, const u8 *mac_addr, struct key_params *params) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct wl_wsec_key key; ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ s32 mode = wl_get_mode_by_netdev(wl, dev); ++ memset(&key, 0, sizeof(key)); ++ key.index = (u32) key_idx; ++ ++ if (!ETHER_ISMULTI(mac_addr)) ++ memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN); ++ key.len = (u32) params->key_len; ++ ++ /* check for key index change */ ++ if (key.len == 0) { ++ /* key delete */ ++ swap_key_from_BE(&key); ++ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ if (unlikely(err)) { ++ AP6211_ERR("key delete error (%d)\n", err); ++ return err; ++ } ++ } else { ++ if (key.len > sizeof(key.data)) { ++ AP6211_ERR("Invalid key length (%d)\n", key.len); ++ return -EINVAL; ++ } ++ AP6211_DEBUG("Setting the key index %d\n", key.index); ++ memcpy(key.data, params->key, key.len); ++ ++ if ((mode == WL_MODE_BSS) && ++ (params->cipher == WLAN_CIPHER_SUITE_TKIP)) { ++ u8 keybuf[8]; ++ memcpy(keybuf, &key.data[24], sizeof(keybuf)); ++ memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); ++ memcpy(&key.data[16], keybuf, sizeof(keybuf)); ++ } ++ ++ /* if IW_ENCODE_EXT_RX_SEQ_VALID set */ ++ if (params->seq && params->seq_len == 6) { ++ /* rx iv */ ++ u8 *ivptr; ++ ivptr = (u8 *) params->seq; ++ key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | ++ (ivptr[3] << 8) | ivptr[2]; ++ key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; ++ key.iv_initialized = true; ++ } ++ ++ switch (params->cipher) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ key.algo = CRYPTO_ALGO_WEP1; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_WEP40\n"); ++ break; ++ case WLAN_CIPHER_SUITE_WEP104: ++ key.algo = CRYPTO_ALGO_WEP128; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_WEP104\n"); ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ key.algo = CRYPTO_ALGO_TKIP; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_TKIP\n"); ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ key.algo = CRYPTO_ALGO_AES_CCM; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_AES_CMAC\n"); ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ key.algo = CRYPTO_ALGO_AES_CCM; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_CCMP\n"); ++ break; ++#ifdef BCMWAPI_WPI ++ case WLAN_CIPHER_SUITE_SMS4: ++ key.algo = CRYPTO_ALGO_SMS4; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_SMS4\n"); ++ break; ++#endif ++ default: ++ AP6211_ERR("Invalid cipher (0x%x)\n", params->cipher); ++ return -EINVAL; ++ } ++ swap_key_from_BE(&key); ++ /* need to guarantee EAPOL 4/4 send out before set key */ ++ dhd_wait_pend8021x(dev); ++ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_SET_KEY error (%d)\n", err); ++ return err; ++ } ++ } ++ return err; ++} ++ ++static s32 ++wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, bool pairwise, const u8 *mac_addr, ++ struct key_params *params) ++{ ++ struct wl_wsec_key key; ++ s32 val = 0; ++ s32 wsec = 0; ++ s32 err = 0; ++ u8 keybuf[8]; ++ s32 bssidx = 0; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ s32 mode = wl_get_mode_by_netdev(wl, dev); ++ AP6211_DEBUG("key index (%d)\n", key_idx); ++ CHECK_SYS_UP(wl); ++ ++ bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ if (mac_addr) { ++ wl_add_keyext(wiphy, dev, key_idx, mac_addr, params); ++ goto exit; ++ } ++ memset(&key, 0, sizeof(key)); ++ ++ key.len = (u32) params->key_len; ++ key.index = (u32) key_idx; ++ ++ if (unlikely(key.len > sizeof(key.data))) { ++ AP6211_ERR("Too long key length (%u)\n", key.len); ++ return -EINVAL; ++ } ++ memcpy(key.data, params->key, key.len); ++ ++ key.flags = WL_PRIMARY_KEY; ++ switch (params->cipher) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ key.algo = CRYPTO_ALGO_WEP1; ++ val = WEP_ENABLED; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_WEP40\n"); ++ break; ++ case WLAN_CIPHER_SUITE_WEP104: ++ key.algo = CRYPTO_ALGO_WEP128; ++ val = WEP_ENABLED; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_WEP104\n"); ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ key.algo = CRYPTO_ALGO_TKIP; ++ val = TKIP_ENABLED; ++ /* wpa_supplicant switches the third and fourth quarters of the TKIP key */ ++ if (mode == WL_MODE_BSS) { ++ bcopy(&key.data[24], keybuf, sizeof(keybuf)); ++ bcopy(&key.data[16], &key.data[24], sizeof(keybuf)); ++ bcopy(keybuf, &key.data[16], sizeof(keybuf)); ++ } ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_TKIP\n"); ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ key.algo = CRYPTO_ALGO_AES_CCM; ++ val = AES_ENABLED; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_AES_CMAC\n"); ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ key.algo = CRYPTO_ALGO_AES_CCM; ++ val = AES_ENABLED; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_CCMP\n"); ++ break; ++#ifdef BCMWAPI_WPI ++ case WLAN_CIPHER_SUITE_SMS4: ++ key.algo = CRYPTO_ALGO_SMS4; ++ val = SMS4_ENABLED; ++ AP6211_DEBUG(" * wl_cfg80211_add_key, set key " ++ " to WLAN_CIPHER_SUITE_SMS4\n"); ++ break; ++#endif /* BCMWAPI_WPI */ ++ default: ++ AP6211_ERR("Invalid cipher (0x%x)\n", params->cipher); ++ return -EINVAL; ++ } ++ ++ /* Set the new key/index */ ++ swap_key_from_BE(&key); ++ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf, ++ WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_SET_KEY error (%d)\n", err); ++ return err; ++ } ++ ++exit: ++ err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); ++ if (unlikely(err)) { ++ AP6211_ERR("get wsec error (%d)\n", err); ++ return err; ++ } ++ ++ wsec |= val; ++ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); ++ if (unlikely(err)) { ++ AP6211_ERR("set wsec error (%d)\n", err); ++ return err; ++ } ++ ++ return err; ++} ++ ++static s32 ++wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, bool pairwise, const u8 *mac_addr) ++{ ++ struct wl_wsec_key key; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ AP6211_DEBUG("Enter\n"); ++#ifndef IEEE80211W ++ if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2)) ++ return -EINVAL; ++#endif ++ CHECK_SYS_UP(wl); ++ memset(&key, 0, sizeof(key)); ++ ++ key.flags = WL_PRIMARY_KEY; ++ key.algo = CRYPTO_ALGO_OFF; ++ key.index = (u32) key_idx; ++ ++ AP6211_DEBUG("key index (%d)\n", key_idx); ++ /* Set the new key/index */ ++ swap_key_from_BE(&key); ++ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf, ++ WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ if (unlikely(err)) { ++ if (err == -EINVAL) { ++ if (key.index >= DOT11_MAX_DEFAULT_KEYS) { ++ /* we ignore this key index in this case */ ++ AP6211_DEBUG("invalid key index (%d)\n", key_idx); ++ } ++ } else { ++ AP6211_ERR("WLC_SET_KEY error (%d)\n", err); ++ } ++ return err; ++ } ++ return err; ++} ++ ++static s32 ++wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, ++ u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, ++ void (*callback) (void *cookie, struct key_params * params)) ++{ ++ struct key_params params; ++ struct wl_wsec_key key; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct wl_security *sec; ++ s32 wsec; ++ s32 err = 0; ++ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); ++ ++ AP6211_DEBUG("key index (%d)\n", key_idx); ++ CHECK_SYS_UP(wl); ++ memset(&key, 0, sizeof(key)); ++ key.index = key_idx; ++ swap_key_to_BE(&key); ++ memset(¶ms, 0, sizeof(params)); ++ params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len); ++ memcpy(params.key, key.data, params.key_len); ++ ++ wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_GET_WSEC error (%d)\n", err); ++ return err; ++ } ++ switch (wsec & ~SES_OW_ENABLED) { ++ case WEP_ENABLED: ++ sec = wl_read_prof(wl, dev, WL_PROF_SEC); ++ if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { ++ params.cipher = WLAN_CIPHER_SUITE_WEP40; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_WEP40\n"); ++ } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { ++ params.cipher = WLAN_CIPHER_SUITE_WEP104; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_WEP104\n"); ++ } ++ break; ++ case TKIP_ENABLED: ++ params.cipher = WLAN_CIPHER_SUITE_TKIP; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_TKIP\n"); ++ break; ++ case AES_ENABLED: ++ params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; ++ AP6211_DEBUG("WLAN_CIPHER_SUITE_AES_CMAC\n"); ++ break; ++#ifdef BCMWAPI_WPI ++ case WLAN_CIPHER_SUITE_SMS4: ++ key.algo = CRYPTO_ALGO_SMS4; ++ AP6211_DEBUG(" * wl_cfg80211_add_key, set key" ++ "to WLAN_CIPHER_SUITE_SMS4\n"); ++ break; ++#endif ++ default: ++ AP6211_ERR("Invalid algo (0x%x)\n", wsec); ++ return -EINVAL; ++ } ++ ++ callback(cookie, ¶ms); ++ return err; ++} ++ ++static s32 ++wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, ++ struct net_device *dev, u8 key_idx) ++{ ++ AP6211_DEBUG("Not supported\n"); ++ return -EOPNOTSUPP; ++} ++ ++static s32 ++wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, ++ u8 *mac, struct station_info *sinfo) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ scb_val_t scb_val; ++ s32 rssi; ++ s32 rate; ++ s32 err = 0; ++ sta_info_t *sta; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) ++ s8 eabuf[ETHER_ADDR_STR_LEN]; ++#endif ++ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); ++ CHECK_SYS_UP(wl); ++ if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) { ++ err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac, ++ ETHER_ADDR_LEN, wl->ioctl_buf, WLC_IOCTL_SMLEN, &wl->ioctl_buf_sync); ++ if (err < 0) { ++ AP6211_ERR("GET STA INFO failed, %d\n", err); ++ return err; ++ } ++ sinfo->filled = STATION_INFO_INACTIVE_TIME; ++ sta = (sta_info_t *)wl->ioctl_buf; ++ sta->len = dtoh16(sta->len); ++ sta->cap = dtoh16(sta->cap); ++ sta->flags = dtoh32(sta->flags); ++ sta->idle = dtoh32(sta->idle); ++ sta->in = dtoh32(sta->in); ++ sinfo->inactive_time = sta->idle * 1000; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) ++ if (sta->flags & WL_STA_ASSOC) { ++ sinfo->filled |= STATION_INFO_CONNECTED_TIME; ++ sinfo->connected_time = sta->in; ++ } ++ AP6211_DEBUG("STA %s : idle time : %d sec, connected time :%d ms\n", ++ bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time, ++ sta->idle * 1000); ++#endif ++ } else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS) { ++ get_pktcnt_t pktcnt; ++ u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID); ++ if (!wl_get_drv_status(wl, CONNECTED, dev) || ++ (dhd_is_associated(dhd, NULL, &err) == FALSE)) { ++ AP6211_ERR("NOT assoc\n"); ++ if (err == -ERESTARTSYS) ++ return err; ++ err = -ENODEV; ++ return err; ++ } ++ if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) { ++ AP6211_ERR("Wrong Mac address: "MACDBG" != "MACDBG"\n", ++ MAC2STRDBG(mac), MAC2STRDBG(curmacp)); ++ } ++ ++ /* Report the current tx rate */ ++ err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false); ++ if (err) { ++ AP6211_ERR("Could not get rate (%d)\n", err); ++ } else { ++ rate = dtoh32(rate); ++ sinfo->filled |= STATION_INFO_TX_BITRATE; ++ sinfo->txrate.legacy = rate * 5; ++ AP6211_DEBUG("Rate %d Mbps\n", (rate / 2)); ++ } ++ ++ memset(&scb_val, 0, sizeof(scb_val)); ++ scb_val.val = 0; ++ err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, ++ sizeof(scb_val_t), false); ++ if (err) { ++ AP6211_ERR("Could not get rssi (%d)\n", err); ++ goto get_station_err; ++ } ++ rssi = dtoh32(scb_val.val); ++#if defined(RSSIOFFSET) ++ rssi = wl_update_rssi_offset(rssi); ++#endif ++ sinfo->filled |= STATION_INFO_SIGNAL; ++ sinfo->signal = rssi; ++ AP6211_DEBUG("RSSI %d dBm\n", rssi); ++ err = wldev_ioctl(dev, WLC_GET_PKTCNTS, &pktcnt, ++ sizeof(pktcnt), false); ++ if (!err) { ++ sinfo->filled |= (STATION_INFO_RX_PACKETS | ++ STATION_INFO_RX_DROP_MISC | ++ STATION_INFO_TX_PACKETS | ++ STATION_INFO_TX_FAILED); ++ sinfo->rx_packets = pktcnt.rx_good_pkt; ++ sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt; ++ sinfo->tx_packets = pktcnt.tx_good_pkt; ++ sinfo->tx_failed = pktcnt.tx_bad_pkt; ++ } ++get_station_err: ++ if (err && (err != -ERESTARTSYS)) { ++ /* Disconnect due to zero BSSID or error to get RSSI */ ++ AP6211_ERR("force cfg80211_disconnected\n"); ++ wl_clr_drv_status(wl, CONNECTED, dev); ++ cfg80211_disconnected(dev, 0, NULL, 0, GFP_KERNEL); ++ wl_link_down(wl); ++ } ++ } ++ ++ return err; ++} ++ ++/* Function to update sta power save mode for Kernel wifi stack */ ++int wl_cfg80211_update_power_mode(struct net_device *dev) ++{ ++ int pm = -1; ++ int err; ++ ++ err = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), false); ++ if (err || (pm == -1)) { ++ AP6211_ERR("error (%d)\n", err); ++ } else { ++ pm = (pm == PM_OFF) ? false : true; ++ AP6211_DEBUG("%s: %d\n", __func__, pm); ++ if (dev->ieee80211_ptr) ++ dev->ieee80211_ptr->ps = pm; ++ } ++ return err; ++} ++ ++static s32 ++wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, ++ bool enabled, s32 timeout) ++{ ++ s32 pm; ++ s32 err = 0; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct net_info *_net_info = wl_get_netinfo_by_netdev(wl, dev); ++#if !defined(SUPPORT_PM2_ONLY) ++ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); ++#endif /* (OEM_ANDROID) */ ++ CHECK_SYS_UP(wl); ++ ++ if (wl->p2p_net == dev || _net_info == NULL) { ++ return err; ++ } ++ AP6211_DEBUG("%s: Enter power save enabled %d\n", dev->name, enabled); ++ ++#if !defined(SUPPORT_PM2_ONLY) ++ /* android has special hooks to change pm when kernel suspended */ ++ pm = enabled ? ((dhd->in_suspend) ? PM_MAX : PM_FAST) : PM_OFF; ++#else ++ pm = enabled ? PM_FAST : PM_OFF; ++#endif /* SUPPORT_PM2_ONLY */ ++ ++ if (_net_info->pm_block || wl->vsdb_mode) { ++ /* Do not enable the power save if it is p2p interface or vsdb mode is set */ ++ AP6211_DEBUG("%s:Do not enable the power save for pm_block %d or vsdb_mode %d\n", ++ dev->name, _net_info->pm_block, wl->vsdb_mode); ++ pm = PM_OFF; ++ } ++ pm = htod32(pm); ++ AP6211_DEBUG("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled")); ++ err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true); ++ if (unlikely(err)) { ++ if (err == -ENODEV) ++ AP6211_DEBUG("net_device is not ready yet\n"); ++ else ++ AP6211_ERR("error (%d)\n", err); ++ return err; ++ } ++ return err; ++} ++ ++static __used u32 wl_find_msb(u16 bit16) ++{ ++ u32 ret = 0; ++ ++ if (bit16 & 0xff00) { ++ ret += 8; ++ bit16 >>= 8; ++ } ++ ++ if (bit16 & 0xf0) { ++ ret += 4; ++ bit16 >>= 4; ++ } ++ ++ if (bit16 & 0xc) { ++ ret += 2; ++ bit16 >>= 2; ++ } ++ ++ if (bit16 & 2) ++ ret += bit16 & 2; ++ else if (bit16) ++ ret += bit16; ++ ++ return ret; ++} ++ ++static s32 wl_cfg80211_resume(struct wiphy *wiphy) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ s32 err = 0; ++ ++ if (unlikely(!wl_get_drv_status(wl, READY, ndev))) { ++ AP6211_DEBUG("device is not ready\n"); ++ return 0; ++ } ++ ++ wl_invoke_iscan(wl); ++ ++ return err; ++} ++ ++static s32 ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) ++wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) ++#else ++wl_cfg80211_suspend(struct wiphy *wiphy) ++#endif ++{ ++#ifdef DHD_CLEAR_ON_SUSPEND ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct net_info *iter, *next; ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ unsigned long flags; ++ if (unlikely(!wl_get_drv_status(wl, READY, ndev))) { ++ AP6211_DEBUG("device is not ready : status (%d)\n", ++ (int)wl->status); ++ return 0; ++ } ++ for_each_ndev(wl, iter, next) ++ wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev); ++ wl_term_iscan(wl); ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ if (wl->scan_request) { ++ cfg80211_scan_done(wl->scan_request, true); ++ wl->scan_request = NULL; ++ } ++ for_each_ndev(wl, iter, next) { ++ wl_clr_drv_status(wl, SCANNING, iter->ndev); ++ wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev); ++ } ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ for_each_ndev(wl, iter, next) { ++ if (wl_get_drv_status(wl, CONNECTING, iter->ndev)) { ++ wl_bss_connect_done(wl, iter->ndev, NULL, NULL, false); ++ } ++ } ++#endif /* DHD_CLEAR_ON_SUSPEND */ ++ return 0; ++} ++ ++static s32 ++wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, ++ s32 err) ++{ ++ int i, j; ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct net_device *primary_dev = wl_to_prmry_ndev(wl); ++ ++ if (!pmk_list) { ++ AP6211_DEBUG("pmk_list is NULL\n"); ++ return -EINVAL; ++ } ++ /* pmk list is supported only for STA interface i.e. primary interface ++ * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init ++ */ ++ if (primary_dev != dev) { ++ AP6211_DEBUG("Not supporting Flushing pmklist on virtual" ++ " interfaces than primary interface\n"); ++ return err; ++ } ++ ++ AP6211_DEBUG("No of elements %d\n", pmk_list->pmkids.npmkid); ++ for (i = 0; i < pmk_list->pmkids.npmkid; i++) { ++ AP6211_DEBUG("PMKID[%d]: %pM =\n", i, ++ &pmk_list->pmkids.pmkid[i].BSSID); ++ for (j = 0; j < WPA2_PMKID_LEN; j++) { ++ AP6211_DEBUG("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]); ++ } ++ } ++ if (likely(!err)) { ++ err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list, ++ sizeof(*pmk_list), wl->ioctl_buf, WLC_IOCTL_MAXLEN, NULL); ++ } ++ ++ return err; ++} ++ ++static s32 ++wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_pmksa *pmksa) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ s32 err = 0; ++ int i; ++ ++ CHECK_SYS_UP(wl); ++ for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++) ++ if (!memcmp(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID, ++ ETHER_ADDR_LEN)) ++ break; ++ if (i < WL_NUM_PMKIDS_MAX) { ++ memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid, ++ ETHER_ADDR_LEN); ++ memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid, ++ WPA2_PMKID_LEN); ++ if (i == wl->pmk_list->pmkids.npmkid) ++ wl->pmk_list->pmkids.npmkid++; ++ } else { ++ err = -EINVAL; ++ } ++ AP6211_DEBUG("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", ++ &wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid - 1].BSSID); ++ for (i = 0; i < WPA2_PMKID_LEN; i++) { ++ AP6211_DEBUG("%02x\n", ++ wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid - 1]. ++ PMKID[i]); ++ } ++ ++ err = wl_update_pmklist(dev, wl->pmk_list, err); ++ ++ return err; ++} ++ ++static s32 ++wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_pmksa *pmksa) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct _pmkid_list pmkid; ++ s32 err = 0; ++ int i; ++ ++ CHECK_SYS_UP(wl); ++ memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN); ++ memcpy(pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); ++ ++ AP6211_DEBUG("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", ++ &pmkid.pmkid[0].BSSID); ++ for (i = 0; i < WPA2_PMKID_LEN; i++) { ++ AP6211_DEBUG("%02x\n", pmkid.pmkid[0].PMKID[i]); ++ } ++ ++ for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++) ++ if (!memcmp ++ (pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID, ++ ETHER_ADDR_LEN)) ++ break; ++ ++ if ((wl->pmk_list->pmkids.npmkid > 0) && ++ (i < wl->pmk_list->pmkids.npmkid)) { ++ memset(&wl->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t)); ++ for (; i < (wl->pmk_list->pmkids.npmkid - 1); i++) { ++ memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, ++ &wl->pmk_list->pmkids.pmkid[i + 1].BSSID, ++ ETHER_ADDR_LEN); ++ memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, ++ &wl->pmk_list->pmkids.pmkid[i + 1].PMKID, ++ WPA2_PMKID_LEN); ++ } ++ wl->pmk_list->pmkids.npmkid--; ++ } else { ++ err = -EINVAL; ++ } ++ ++ err = wl_update_pmklist(dev, wl->pmk_list, err); ++ ++ return err; ++ ++} ++ ++static s32 ++wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ s32 err = 0; ++ CHECK_SYS_UP(wl); ++ memset(wl->pmk_list, 0, sizeof(*wl->pmk_list)); ++ err = wl_update_pmklist(dev, wl->pmk_list, err); ++ return err; ++ ++} ++ ++static wl_scan_params_t * ++wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size) ++{ ++ wl_scan_params_t *params; ++ int params_size; ++ int num_chans; ++ ++ *out_params_size = 0; ++ ++ /* Our scan params only need space for 1 channel and 0 ssids */ ++ params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16); ++ params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL); ++ if (params == NULL) { ++ AP6211_ERR("%s: mem alloc failed (%d bytes)\n", __func__, params_size); ++ return params; ++ } ++ memset(params, 0, params_size); ++ params->nprobes = nprobes; ++ ++ num_chans = (channel == 0) ? 0 : 1; ++ ++ memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); ++ params->bss_type = DOT11_BSSTYPE_ANY; ++ params->scan_type = DOT11_SCANTYPE_ACTIVE; ++ params->nprobes = htod32(1); ++ params->active_time = htod32(-1); ++ params->passive_time = htod32(-1); ++ params->home_time = htod32(10); ++ if (channel == -1) ++ params->channel_list[0] = htodchanspec(channel); ++ else ++ params->channel_list[0] = wl_ch_host_to_driver(channel); ++ ++ /* Our scan params have 1 channel and 0 ssids */ ++ params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | ++ (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); ++ ++ *out_params_size = params_size; /* rtn size to the caller */ ++ return params; ++} ++ ++static s32 ++wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, ++ struct ieee80211_channel * channel, ++ enum nl80211_channel_type channel_type, ++ unsigned int duration, u64 *cookie) ++{ ++ s32 target_channel; ++ u32 id; ++ struct ether_addr primary_mac; ++ struct net_device *ndev = NULL; ++ ++ s32 err = BCME_OK; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ ++ AP6211_DEBUG("Enter, ifindex: %d, channel: %d, duration ms (%d) SCANNING ?? %s \n", ++ dev->ifindex, ieee80211_frequency_to_channel(channel->center_freq), ++ duration, (wl_get_drv_status(wl, SCANNING, ndev)) ? "YES":"NO"); ++ ++ if (wl->p2p_net == dev) { ++ ndev = wl_to_prmry_ndev(wl); ++ } else { ++ ndev = dev; ++ } ++ ++ if (!wl->p2p) { ++ AP6211_ERR("wl->p2p is not initialized\n"); ++ err = BCME_ERROR; ++ goto exit; ++ } ++ ++#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ if (wl_get_drv_status(wl, SCANNING, ndev)) { ++ wl_notify_escan_complete(wl, ndev, true, true); ++ } ++#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ ++ target_channel = ieee80211_frequency_to_channel(channel->center_freq); ++ memcpy(&wl->remain_on_chan, channel, sizeof(struct ieee80211_channel)); ++ wl->remain_on_chan_type = channel_type; ++ id = ++wl->last_roc_id; ++ if (id == 0) ++ id = ++wl->last_roc_id; ++ *cookie = id; ++ ++#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ if (wl_get_drv_status(wl, SCANNING, ndev)) { ++ struct timer_list *_timer; ++ AP6211_DEBUG("scan is running. go to fake listen state\n"); ++ ++ wl_set_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, ndev); ++ ++ if (timer_pending(&wl->p2p->listen_timer)) { ++ AP6211_DEBUG("cancel current listen timer \n"); ++ del_timer_sync(&wl->p2p->listen_timer); ++ } ++ ++ _timer = &wl->p2p->listen_timer; ++ wl_clr_p2p_status(wl, LISTEN_EXPIRED); ++ ++ INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0); ++ ++ err = BCME_OK; ++ goto exit; ++ } ++#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ ++#ifdef WL_CFG80211_SYNC_GON ++ if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) { ++ /* do not enter listen mode again if we are in listen mode already for next af. ++ * remain on channel completion will be returned by waiting next af completion. ++ */ ++#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ wl_set_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, ndev); ++#else ++ wl_set_drv_status(wl, REMAINING_ON_CHANNEL, ndev); ++#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ goto exit; ++ } ++#endif /* WL_CFG80211_SYNC_GON */ ++ if (wl->p2p && !wl->p2p->on) { ++ /* In case of p2p_listen command, supplicant send remain_on_channel ++ * without turning on P2P ++ */ ++ get_primary_mac(wl, &primary_mac); ++ wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); ++ p2p_on(wl) = true; ++ } ++ ++ if (p2p_is_on(wl)) { ++ err = wl_cfgp2p_enable_discovery(wl, ndev, NULL, 0); ++ if (unlikely(err)) { ++ goto exit; ++ } ++#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ wl_set_drv_status(wl, REMAINING_ON_CHANNEL, ndev); ++#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ err = wl_cfgp2p_discover_listen(wl, target_channel, duration); ++ ++#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ if (err == BCME_OK) { ++ wl_set_drv_status(wl, REMAINING_ON_CHANNEL, ndev); ++ } else { ++ /* if failed, firmware may be internal scanning state. ++ * so other scan request shall not abort it ++ */ ++ wl_set_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, ndev); ++ } ++#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant ++ * and expire timer will send a completion to the upper layer ++ */ ++ err = BCME_OK; ++ } ++ ++exit: ++ if (err == BCME_OK) { ++ AP6211_DEBUG("Success\n"); ++ cfg80211_ready_on_channel(dev, *cookie, channel, ++ channel_type, duration, GFP_KERNEL); ++ } else { ++ AP6211_ERR("Fail to Set (err=%d cookie:%llu)\n", err, *cookie); ++ } ++ return err; ++} ++ ++static s32 ++wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, ++ u64 cookie) ++{ ++ s32 err = 0; ++ AP6211_DEBUG(" enter ) netdev_ifidx: %d \n", dev->ifindex); ++ return err; ++} ++ ++static void ++wl_cfg80211_afx_handler(struct work_struct *work) ++{ ++ struct afx_hdl *afx_instance; ++ struct wl_priv *wl = wlcfg_drv_priv; ++ s32 ret = BCME_OK; ++ ++ afx_instance = container_of(work, struct afx_hdl, work); ++ if (afx_instance != NULL && wl->afx_hdl->is_active) { ++ if (wl->afx_hdl->is_listen && wl->afx_hdl->my_listen_chan) { ++ ret = wl_cfgp2p_discover_listen(wl, wl->afx_hdl->my_listen_chan, ++ (100 * (1 + (random32() % 3)))); /* 100ms ~ 300ms */ ++ } else { ++ ret = wl_cfgp2p_act_frm_search(wl, wl->afx_hdl->dev, ++ wl->afx_hdl->bssidx, wl->afx_hdl->peer_listen_chan); ++ } ++ if (unlikely(ret != BCME_OK)) { ++ AP6211_ERR("ERROR occurred! returned value is (%d)\n", ret); ++ if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) ++ complete(&wl->act_frm_scan); ++ } ++ } ++} ++ ++static s32 ++wl_cfg80211_af_searching_channel(struct wl_priv *wl, struct net_device *dev) ++{ ++ u32 max_retry = WL_CHANNEL_SYNC_RETRY; ++ ++ if (dev == NULL) ++ return -1; ++ ++ AP6211_DEBUG(" enter ) \n"); ++ ++ wl_set_drv_status(wl, FINDING_COMMON_CHANNEL, dev); ++ wl->afx_hdl->is_active = TRUE; ++ ++ /* Loop to wait until we find a peer's channel or the ++ * pending action frame tx is cancelled. ++ */ ++ while ((wl->afx_hdl->retry < max_retry) && ++ (wl->afx_hdl->peer_chan == WL_INVALID)) { ++ wl->afx_hdl->is_listen = FALSE; ++ wl_set_drv_status(wl, SCANNING, dev); ++ AP6211_DEBUG("Scheduling the action frame for sending.. retry %d\n", ++ wl->afx_hdl->retry); ++ /* search peer on peer's listen channel */ ++ schedule_work(&wl->afx_hdl->work); ++ wait_for_completion_timeout(&wl->act_frm_scan, ++ msecs_to_jiffies(MAX_WAIT_TIME)); ++ ++ if ((wl->afx_hdl->peer_chan != WL_INVALID) || ++ !(wl_get_drv_status(wl, FINDING_COMMON_CHANNEL, dev))) ++ break; ++ ++ if (wl->afx_hdl->my_listen_chan) { ++ AP6211_DEBUG("Scheduling Listen peer in my listen channel = %d\n", ++ wl->afx_hdl->my_listen_chan); ++ /* listen on my listen channel */ ++ wl->afx_hdl->is_listen = TRUE; ++ schedule_work(&wl->afx_hdl->work); ++ wait_for_completion_timeout(&wl->act_frm_scan, ++ msecs_to_jiffies(MAX_WAIT_TIME)); ++ } ++ if (!wl_get_drv_status(wl, FINDING_COMMON_CHANNEL, dev)) ++ break; ++ wl->afx_hdl->retry++; ++ ++ WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl); ++ } ++ ++ wl->afx_hdl->is_active = FALSE; ++ ++ wl_clr_drv_status(wl, SCANNING, dev); ++ wl_clr_drv_status(wl, FINDING_COMMON_CHANNEL, dev); ++ ++ return (wl->afx_hdl->peer_chan); ++} ++ ++struct p2p_config_af_params { ++ s32 max_tx_retry; /* max tx retry count if tx no ack */ ++ /* To make sure to send successfully action frame, we have to turn off mpc ++ * 0: off, 1: on, (-1): do nothing ++ */ ++ s32 mpc_onoff; ++#ifdef WL_CFG80211_SYNC_GON ++ bool extra_listen; ++#endif ++ bool search_channel; /* 1: search peer's channel to send af */ ++}; ++ ++static s32 ++wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy, ++ wl_action_frame_t *action_frame, wl_af_params_t *af_params, ++ struct p2p_config_af_params *config_af_params) ++{ ++ s32 err = BCME_OK; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ wifi_p2p_pub_act_frame_t *act_frm = ++ (wifi_p2p_pub_act_frame_t *) (action_frame->data); ++ ++ /* initialize default value */ ++#ifdef WL_CFG80211_SYNC_GON ++ config_af_params->extra_listen = true; ++#endif ++ config_af_params->search_channel = false; ++ config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY; ++ config_af_params->mpc_onoff = -1; ++ ++ switch (act_frm->subtype) { ++ case P2P_PAF_GON_REQ: { ++ AP6211_DEBUG("P2P: GO_NEG_PHASE status set \n"); ++ wl_set_p2p_status(wl, GO_NEG_PHASE); ++ ++ config_af_params->mpc_onoff = 0; ++ config_af_params->search_channel = true; ++ wl->next_af_subtype = act_frm->subtype + 1; ++ ++ /* increase dwell time to wait for RESP frame */ ++ af_params->dwell_time = WL_MED_DWELL_TIME; ++ ++ break; ++ } ++ case P2P_PAF_GON_RSP: { ++ wl->next_af_subtype = act_frm->subtype + 1; ++ /* increase dwell time to wait for CONF frame */ ++ af_params->dwell_time = WL_MED_DWELL_TIME; ++ break; ++ } ++ case P2P_PAF_GON_CONF: { ++ /* If we reached till GO Neg confirmation reset the filter */ ++ AP6211_DEBUG("P2P: GO_NEG_PHASE status cleared \n"); ++ wl_clr_p2p_status(wl, GO_NEG_PHASE); ++ ++ /* turn on mpc again if go nego is done */ ++ config_af_params->mpc_onoff = 1; ++ ++ /* minimize dwell time */ ++ af_params->dwell_time = WL_MIN_DWELL_TIME; ++ ++#ifdef WL_CFG80211_SYNC_GON ++ config_af_params->extra_listen = false; ++#endif /* WL_CFG80211_SYNC_GON */ ++ break; ++ } ++ case P2P_PAF_INVITE_REQ: { ++ config_af_params->search_channel = true; ++ wl->next_af_subtype = act_frm->subtype + 1; ++ ++ /* increase dwell time */ ++ af_params->dwell_time = WL_MED_DWELL_TIME; ++ break; ++ } ++ case P2P_PAF_INVITE_RSP: ++ /* minimize dwell time */ ++ af_params->dwell_time = WL_MIN_DWELL_TIME; ++#ifdef WL_CFG80211_SYNC_GON ++ config_af_params->extra_listen = false; ++#endif /* WL_CFG80211_SYNC_GON */ ++ break; ++ case P2P_PAF_DEVDIS_REQ: { ++ config_af_params->search_channel = true; ++ ++ wl->next_af_subtype = act_frm->subtype + 1; ++ /* maximize dwell time to wait for RESP frame */ ++ af_params->dwell_time = WL_LONG_DWELL_TIME; ++ break; ++ } ++ case P2P_PAF_DEVDIS_RSP: ++ /* minimize dwell time */ ++ af_params->dwell_time = WL_MIN_DWELL_TIME; ++#ifdef WL_CFG80211_SYNC_GON ++ config_af_params->extra_listen = false; ++#endif /* WL_CFG80211_SYNC_GON */ ++ break; ++ case P2P_PAF_PROVDIS_REQ: { ++ if (IS_PROV_DISC_WITHOUT_GROUP_ID(&act_frm->elts[0], ++ action_frame->len)) { ++ config_af_params->search_channel = true; ++ } ++ ++ config_af_params->mpc_onoff = 0; ++ wl->next_af_subtype = act_frm->subtype + 1; ++ /* increase dwell time to wait for RESP frame */ ++ af_params->dwell_time = WL_MED_DWELL_TIME; ++ break; ++ } ++ case P2P_PAF_PROVDIS_RSP: { ++ wl->next_af_subtype = P2P_PAF_GON_REQ; ++ /* increase dwell time to MED level */ ++ af_params->dwell_time = WL_MED_DWELL_TIME; ++#ifdef WL_CFG80211_SYNC_GON ++ config_af_params->extra_listen = false; ++#endif /* WL_CFG80211_SYNC_GON */ ++ break; ++ } ++ default: ++ AP6211_DEBUG("Unknown p2p pub act frame subtype: %d\n", ++ act_frm->subtype); ++ err = BCME_BADARG; ++ } ++ return err; ++} ++ ++ ++static bool ++wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, ++ struct net_device *ndev, wl_af_params_t *af_params, ++ wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ bool ack = false; ++ u8 category, action; ++ s32 tx_retry; ++ struct p2p_config_af_params config_af_params; ++#ifdef VSDB ++ ulong off_chan_started_jiffies = 0; ++#endif ++ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); ++ ++ wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len); ++ ++ category = action_frame->data[DOT11_ACTION_CAT_OFF]; ++ action = action_frame->data[DOT11_ACTION_ACT_OFF]; ++ ++ /* initialize variables */ ++ tx_retry = 0; ++ wl->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; ++ config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY; ++ config_af_params.mpc_onoff = -1; ++ config_af_params.search_channel = false; ++#ifdef WL_CFG80211_SYNC_GON ++ config_af_params.extra_listen = false; ++#endif ++ ++ /* config parameters */ ++ /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */ ++ if (category == DOT11_ACTION_CAT_PUBLIC) { ++ if ((action == P2P_PUB_AF_ACTION) && ++ (action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) { ++ /* p2p public action frame process */ ++ if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy, ++ action_frame, af_params, &config_af_params)) { ++ AP6211_DEBUG("Unknown subtype.\n"); ++ } ++ ++ } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) { ++ /* service discovery process */ ++ if (action == P2PSD_ACTION_ID_GAS_IREQ || ++ action == P2PSD_ACTION_ID_GAS_CREQ) { ++ /* configure service discovery query frame */ ++ ++ config_af_params.search_channel = true; ++ ++ /* save next af suptype to cancel remained dwell time */ ++ wl->next_af_subtype = action + 1; ++ ++ af_params->dwell_time = WL_MED_DWELL_TIME; ++ } else if (action == P2PSD_ACTION_ID_GAS_IRESP || ++ action == P2PSD_ACTION_ID_GAS_CRESP) { ++ /* configure service discovery response frame */ ++ af_params->dwell_time = WL_MIN_DWELL_TIME; ++ } else { ++ AP6211_DEBUG("Unknown action type: %d\n", action); ++ } ++ } else { ++ AP6211_DEBUG("Unknown Frame: category 0x%x, action 0x%x, length %d\n", ++ category, action, action_frame_len); ++ } ++ } else if (category == P2P_AF_CATEGORY) { ++ /* do not configure anything. it will be sent with a default configuration */ ++ } else { ++ AP6211_DEBUG("Unknown Frame: category 0x%x, action 0x%x\n", ++ category, action); ++ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { ++ wl_clr_drv_status(wl, SENDING_ACT_FRM, dev); ++ return false; ++ } ++ } ++ ++ /* To make sure to send successfully action frame, we have to turn off mpc */ ++ if (config_af_params.mpc_onoff == 0) { ++ wldev_iovar_setint(dev, "mpc", 0); ++ } ++ ++ /* validate channel and p2p ies */ ++ if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) && ++ wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { ++ config_af_params.search_channel = true; ++ } else { ++ config_af_params.search_channel = false; ++ } ++ ++#ifdef WL11U ++ if (ndev == wl_to_prmry_ndev(wl)) ++ config_af_params.search_channel = false; ++#endif /* WL11U */ ++ ++#ifdef VSDB ++ /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */ ++ if (wl_get_drv_status(wl, CONNECTING, wl_to_prmry_ndev(wl))) { ++ msleep(50); ++ } ++#endif ++ ++ /* if scan is ongoing, abort current scan. */ ++ if (wl_get_drv_status_all(wl, SCANNING)) { ++ wl_notify_escan_complete(wl, ndev, true, true); ++ } ++ ++ /* set status and destination address before sending af */ ++ if (wl->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { ++ /* set this status to cancel the remained dwell time in rx process */ ++ wl_set_drv_status(wl, WAITING_NEXT_ACT_FRM, dev); ++ } ++ wl_set_drv_status(wl, SENDING_ACT_FRM, dev); ++ memcpy(wl->afx_hdl->tx_dst_addr.octet, ++ af_params->action_frame.da.octet, ++ sizeof(wl->afx_hdl->tx_dst_addr.octet)); ++ ++ /* save af_params for rx process */ ++ wl->afx_hdl->pending_tx_act_frm = af_params; ++ ++ /* search peer's channel */ ++ if (config_af_params.search_channel) { ++ /* initialize afx_hdl */ ++ wl->afx_hdl->bssidx = wl_cfgp2p_find_idx(wl, dev); ++ wl->afx_hdl->dev = dev; ++ wl->afx_hdl->retry = 0; ++ wl->afx_hdl->peer_chan = WL_INVALID; ++ ++ if (wl_cfg80211_af_searching_channel(wl, dev) == WL_INVALID) { ++ AP6211_ERR("couldn't find peer's channel.\n"); ++ goto exit; ++ } ++ ++ /* Suspend P2P discovery's search-listen to prevent it from ++ * starting a scan or changing the channel. ++ */ ++ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); ++/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary */ ++#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ wl_notify_escan_complete(wl, dev, true, true); ++#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ wl_cfgp2p_discover_enable_search(wl, false); ++ ++ /* update channel */ ++ af_params->channel = wl->afx_hdl->peer_chan; ++ } ++ ++#ifdef VSDB ++ off_chan_started_jiffies = jiffies; ++#endif /* VSDB */ ++ ++ /* Now send a tx action frame */ ++ ack = wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx) ? false : true; ++ ++ /* if failed, retry it. tx_retry_max value is configure by .... */ ++ while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry)) { ++#ifdef VSDB ++ if (af_params->channel) { ++ if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) > ++ OFF_CHAN_TIME_THRESHOLD_MS) { ++ WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl); ++ off_chan_started_jiffies = jiffies; ++ } ++ } ++#endif /* VSDB */ ++ ack = wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx) ? ++ false : true; ++ } ++ if (ack == false) { ++ AP6211_ERR("Failed to send Action Frame(retry %d)\n", tx_retry); ++ } ++exit: ++ /* Clear SENDING_ACT_FRM after all sending af is done */ ++ wl_clr_drv_status(wl, SENDING_ACT_FRM, dev); ++ ++#ifdef WL_CFG80211_SYNC_GON ++ /* WAR: sometimes dongle does not keep the dwell time of 'actframe'. ++ * if we coundn't get the next action response frame and dongle does not keep ++ * the dwell time, go to listen state again to get next action response frame. ++ */ ++ if (ack && config_af_params.extra_listen && ++ wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM) && ++ wl->af_sent_channel == wl->afx_hdl->my_listen_chan) { ++ s32 extar_listen_time; ++ ++ extar_listen_time = af_params->dwell_time - ++ jiffies_to_msecs(jiffies - wl->af_tx_sent_jiffies); ++ ++ if (extar_listen_time > 50) { ++ wl_set_drv_status(wl, WAITING_NEXT_ACT_FRM_LISTEN, dev); ++ AP6211_DEBUG("Wait more time! actual af time:%d," ++ "calculated extar listen:%d\n", ++ af_params->dwell_time, extar_listen_time); ++ if (wl_cfgp2p_discover_listen(wl, wl->af_sent_channel, ++ extar_listen_time + 100) == BCME_OK) { ++ wait_for_completion_timeout(&wl->wait_next_af, ++ msecs_to_jiffies(extar_listen_time + 100 + 300)); ++ } ++ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM_LISTEN, dev); ++ } ++ } ++#endif /* WL_CFG80211_SYNC_GON */ ++ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, dev); ++ ++ if (wl->afx_hdl->pending_tx_act_frm) ++ wl->afx_hdl->pending_tx_act_frm = NULL; ++ ++ AP6211_DEBUG("-- sending Action Frame is %s, listen chan: %d\n", ++ (ack) ? "Succeeded!!":"Failed!!", wl->afx_hdl->my_listen_chan); ++ ++ ++ /* if all done, turn mpc on again */ ++ if (config_af_params.mpc_onoff == 1) { ++ wldev_iovar_setint(dev, "mpc", 1); ++ } ++ ++ return ack; ++} ++ ++static s32 ++wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, ++ struct ieee80211_channel *channel, bool offchan, ++ enum nl80211_channel_type channel_type, ++ bool channel_type_valid, unsigned int wait, ++ const u8* buf, size_t len, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) ++ bool no_cck, ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) ++ bool dont_wait_for_ack, ++#endif ++ u64 *cookie) ++{ ++ wl_action_frame_t *action_frame; ++ wl_af_params_t *af_params; ++ scb_val_t scb_val; ++ const struct ieee80211_mgmt *mgmt; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct net_device *dev = NULL; ++ s32 err = BCME_OK; ++ s32 bssidx = 0; ++ u32 id; ++ bool ack = false; ++ s8 eabuf[ETHER_ADDR_STR_LEN]; ++ ++ AP6211_DEBUG("Enter \n"); ++ ++ if (ndev == wl->p2p_net) { ++ dev = wl_to_prmry_ndev(wl); ++ } else { ++ /* If TX req is for any valid ifidx. Use as is */ ++ dev = ndev; ++ } ++ ++ /* find bssidx based on ndev */ ++ bssidx = wl_cfgp2p_find_idx(wl, dev); ++ if (bssidx == -1) { ++ ++ AP6211_ERR("Can not find the bssidx for dev( %p )\n", dev); ++ return -ENODEV; ++ } ++ if (p2p_is_on(wl)) { ++ /* Suspend P2P discovery search-listen to prevent it from changing the ++ * channel. ++ */ ++ if ((err = wl_cfgp2p_discover_enable_search(wl, false)) < 0) { ++ AP6211_ERR("Can not disable discovery mode\n"); ++ return -EFAULT; ++ } ++ } ++ *cookie = 0; ++ id = wl->send_action_id++; ++ if (id == 0) ++ id = wl->send_action_id++; ++ *cookie = id; ++ mgmt = (const struct ieee80211_mgmt *)buf; ++ if (ieee80211_is_mgmt(mgmt->frame_control)) { ++ if (ieee80211_is_probe_resp(mgmt->frame_control)) { ++ s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; ++ s32 ie_len = len - ie_offset; ++ if (dev == wl_to_prmry_ndev(wl)) ++ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); ++ wl_cfgp2p_set_management_ie(wl, dev, bssidx, ++ VNDR_IE_PRBRSP_FLAG, (u8 *)(buf + ie_offset), ie_len); ++ cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); ++ goto exit; ++ } else if (ieee80211_is_disassoc(mgmt->frame_control) || ++ ieee80211_is_deauth(mgmt->frame_control)) { ++ memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN); ++ scb_val.val = mgmt->u.disassoc.reason_code; ++ err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, ++ sizeof(scb_val_t), true); ++ if (err < 0) ++ AP6211_ERR("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err); ++ AP6211_DEBUG("Disconnect STA : %s scb_val.val %d\n", ++ bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), ++ scb_val.val); ++ wl_delay(400); ++ cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); ++ goto exit; ++ ++ } else if (ieee80211_is_action(mgmt->frame_control)) { ++ /* Abort the dwell time of any previous off-channel ++ * action frame that may be still in effect. Sending ++ * off-channel action frames relies on the driver's ++ * scan engine. If a previous off-channel action frame ++ * tx is still in progress (including the dwell time), ++ * then this new action frame will not be sent out. ++ */ ++/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary. ++ * And previous off-channel action frame must be ended before new af tx. ++ */ ++#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ wl_notify_escan_complete(wl, dev, true, true); ++#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ } ++ ++ } else { ++ AP6211_ERR("Driver only allows MGMT packet type\n"); ++ goto exit; ++ } ++ ++ af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL); ++ ++ if (af_params == NULL) ++ { ++ AP6211_ERR("unable to allocate frame\n"); ++ return -ENOMEM; ++ } ++ ++ action_frame = &af_params->action_frame; ++ ++ /* Add the packet Id */ ++ action_frame->packetId = *cookie; ++ AP6211_DEBUG("action frame %d\n", action_frame->packetId); ++ /* Add BSSID */ ++ memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN); ++ memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN); ++ ++ /* Add the length exepted for 802.11 header */ ++ action_frame->len = len - DOT11_MGMT_HDR_LEN; ++ AP6211_DEBUG("action_frame->len: %d\n", action_frame->len); ++ ++ /* Add the channel */ ++ af_params->channel = ++ ieee80211_frequency_to_channel(channel->center_freq); ++ ++ /* Save listen_chan for searching common channel */ ++ wl->afx_hdl->peer_listen_chan = af_params->channel; ++ AP6211_DEBUG("channel from upper layer %d\n", wl->afx_hdl->peer_listen_chan); ++ ++ /* Add the default dwell time ++ * Dwell time to stay off-channel to wait for a response action frame ++ * after transmitting an GO Negotiation action frame ++ */ ++ af_params->dwell_time = WL_DWELL_TIME; ++ ++ memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); ++ ++ ack = wl_cfg80211_send_action_frame(wiphy, dev, ndev, af_params, ++ action_frame, action_frame->len, bssidx); ++ ++ cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, ack, GFP_KERNEL); ++ ++ kfree(af_params); ++exit: ++ return err; ++} ++ ++ ++static void ++wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, struct net_device *dev, ++ u16 frame_type, bool reg) ++{ ++ ++ AP6211_DEBUG("%s: frame_type: %x, reg: %d\n", __func__, frame_type, reg); ++ ++ if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) ++ return; ++ ++ return; ++} ++ ++ ++static s32 ++wl_cfg80211_change_bss(struct wiphy *wiphy, ++ struct net_device *dev, ++ struct bss_parameters *params) ++{ ++ if (params->use_cts_prot >= 0) { ++ } ++ ++ if (params->use_short_preamble >= 0) { ++ } ++ ++ if (params->use_short_slot_time >= 0) { ++ } ++ ++ if (params->basic_rates) { ++ } ++ ++ if (params->ap_isolate >= 0) { ++ } ++ ++ if (params->ht_opmode >= 0) { ++ } ++ ++ return 0; ++} ++ ++static s32 ++wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, ++ struct ieee80211_channel *chan, ++ enum nl80211_channel_type channel_type) ++{ ++ s32 _chan; ++ chanspec_t chspec = 0; ++ chanspec_t fw_chspec = 0; ++ u32 bw = WL_CHANSPEC_BW_20; ++ ++ s32 err = BCME_OK; ++ s32 bw_cap = 0; ++ struct { ++ u32 band; ++ u32 bw_cap; ++ } param = {0, 0}; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ ++ if (wl->p2p_net == dev) { ++ dev = wl_to_prmry_ndev(wl); ++ } ++ _chan = ieee80211_frequency_to_channel(chan->center_freq); ++ AP6211_ERR("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", ++ dev->ifindex, channel_type, _chan); ++ ++ ++ if (chan->band == IEEE80211_BAND_5GHZ) { ++ param.band = WLC_BAND_5G; ++ err = wldev_iovar_getbuf(dev, "bw_cap", ¶m, sizeof(param), ++ wl->ioctl_buf, WLC_IOCTL_SMLEN, &wl->ioctl_buf_sync); ++ if (err) { ++ if (err != BCME_UNSUPPORTED) { ++ AP6211_ERR("bw_cap failed, %d\n", err); ++ return err; ++ } else { ++ err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); ++ if (err) { ++ AP6211_ERR("error get mimo_bw_cap (%d)\n", err); ++ } ++ if (bw_cap != WLC_N_BW_20ALL) ++ bw = WL_CHANSPEC_BW_40; ++ } ++ } else { ++ if (WL_BW_CAP_80MHZ(wl->ioctl_buf[0])) ++ bw = WL_CHANSPEC_BW_80; ++ else if (WL_BW_CAP_40MHZ(wl->ioctl_buf[0])) ++ bw = WL_CHANSPEC_BW_40; ++ else ++ bw = WL_CHANSPEC_BW_20; ++ ++ } ++ ++ } else if (chan->band == IEEE80211_BAND_2GHZ) ++ bw = WL_CHANSPEC_BW_20; ++set_channel: ++ chspec = wf_channel2chspec(_chan, bw); ++ if (wf_chspec_valid(chspec)) { ++ fw_chspec = wl_chspec_host_to_driver(chspec); ++ if (fw_chspec != INVCHANSPEC) { ++ if ((err = wldev_iovar_setint(dev, "chanspec", ++ fw_chspec)) == BCME_BADCHAN) { ++ if (bw == WL_CHANSPEC_BW_80) ++ goto change_bw; ++ err = wldev_ioctl(dev, WLC_SET_CHANNEL, ++ &_chan, sizeof(_chan), true); ++ if (err < 0) { ++ AP6211_ERR("WLC_SET_CHANNEL error %d" ++ "chip may not be supporting this channel\n", err); ++ } ++ } else if (err) { ++ AP6211_ERR("failed to set chanspec error %d\n", err); ++ } ++ } else { ++ AP6211_ERR("failed to convert host chanspec to fw chanspec\n"); ++ err = BCME_ERROR; ++ } ++ } else { ++change_bw: ++ if (bw == WL_CHANSPEC_BW_80) ++ bw = WL_CHANSPEC_BW_40; ++ else if (bw == WL_CHANSPEC_BW_40) ++ bw = WL_CHANSPEC_BW_20; ++ else ++ bw = 0; ++ if (bw) ++ goto set_channel; ++ AP6211_ERR("Invalid chanspec 0x%x\n", chspec); ++ err = BCME_ERROR; ++ } ++ return err; ++} ++ ++static s32 ++wl_validate_opensecurity(struct net_device *dev, s32 bssidx) ++{ ++ s32 err = BCME_OK; ++ ++ /* set auth */ ++ err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx); ++ if (err < 0) { ++ AP6211_ERR("auth error %d\n", err); ++ return BCME_ERROR; ++ } ++ /* set wsec */ ++ err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); ++ if (err < 0) { ++ AP6211_ERR("wsec error %d\n", err); ++ return BCME_ERROR; ++ } ++ /* set upper-layer auth */ ++ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", WPA_AUTH_NONE, bssidx); ++ if (err < 0) { ++ AP6211_ERR("wpa_auth error %d\n", err); ++ return BCME_ERROR; ++ } ++ ++ return 0; ++} ++ ++static s32 ++wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) ++{ ++ s32 len = 0; ++ s32 err = BCME_OK; ++ u16 auth = 0; /* d11 open authentication */ ++ u32 wsec; ++ u32 pval = 0; ++ u32 gval = 0; ++ u32 wpa_auth = 0; ++ wpa_suite_mcast_t *mcast; ++ wpa_suite_ucast_t *ucast; ++ wpa_suite_auth_key_mgmt_t *mgmt; ++ ++ u16 suite_count; ++ u8 rsn_cap[2]; ++ u32 wme_bss_disable; ++ ++ if (wpa2ie == NULL) ++ goto exit; ++ ++ AP6211_DEBUG("Enter \n"); ++ len = wpa2ie->len; ++ /* check the mcast cipher */ ++ mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; ++ switch (mcast->type) { ++ case WPA_CIPHER_NONE: ++ gval = 0; ++ break; ++ case WPA_CIPHER_WEP_40: ++ case WPA_CIPHER_WEP_104: ++ gval = WEP_ENABLED; ++ break; ++ case WPA_CIPHER_TKIP: ++ gval = TKIP_ENABLED; ++ break; ++ case WPA_CIPHER_AES_CCM: ++ gval = AES_ENABLED; ++ break; ++#ifdef BCMWAPI_WPI ++ case WAPI_CIPHER_SMS4: ++ gval = SMS4_ENABLED; ++ break; ++#endif ++ default: ++ AP6211_ERR("No Security Info\n"); ++ break; ++ } ++ if ((len -= WPA_SUITE_LEN) <= 0) ++ return BCME_BADLEN; ++ ++ /* check the unicast cipher */ ++ ucast = (wpa_suite_ucast_t *)&mcast[1]; ++ suite_count = ltoh16_ua(&ucast->count); ++ switch (ucast->list[0].type) { ++ case WPA_CIPHER_NONE: ++ pval = 0; ++ break; ++ case WPA_CIPHER_WEP_40: ++ case WPA_CIPHER_WEP_104: ++ pval = WEP_ENABLED; ++ break; ++ case WPA_CIPHER_TKIP: ++ pval = TKIP_ENABLED; ++ break; ++ case WPA_CIPHER_AES_CCM: ++ pval = AES_ENABLED; ++ break; ++#ifdef BCMWAPI_WPI ++ case WAPI_CIPHER_SMS4: ++ pval = SMS4_ENABLED; ++ break; ++#endif ++ default: ++ AP6211_ERR("No Security Info\n"); ++ } ++ if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0) ++ return BCME_BADLEN; ++ ++ /* FOR WPS , set SEC_OW_ENABLED */ ++ wsec = (pval | gval | SES_OW_ENABLED); ++ /* check the AKM */ ++ mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count]; ++ suite_count = ltoh16_ua(&mgmt->count); ++ switch (mgmt->list[0].type) { ++ case RSN_AKM_NONE: ++ wpa_auth = WPA_AUTH_NONE; ++ break; ++ case RSN_AKM_UNSPECIFIED: ++ wpa_auth = WPA2_AUTH_UNSPECIFIED; ++ break; ++ case RSN_AKM_PSK: ++ wpa_auth = WPA2_AUTH_PSK; ++ break; ++ default: ++ AP6211_ERR("No Key Mgmt Info\n"); ++ } ++ ++ if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) { ++ rsn_cap[0] = *(u8 *)&mgmt->list[suite_count]; ++ rsn_cap[1] = *((u8 *)&mgmt->list[suite_count] + 1); ++ ++ if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) { ++ wme_bss_disable = 0; ++ } else { ++ wme_bss_disable = 1; ++ } ++ ++ /* set wme_bss_disable to sync RSN Capabilities */ ++ err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx); ++ if (err < 0) { ++ AP6211_ERR("wme_bss_disable error %d\n", err); ++ return BCME_ERROR; ++ } ++ } else { ++ AP6211_DEBUG("There is no RSN Capabilities. remained len %d\n", len); ++ } ++ ++ /* set auth */ ++ err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); ++ if (err < 0) { ++ AP6211_ERR("auth error %d\n", err); ++ return BCME_ERROR; ++ } ++ /* set wsec */ ++ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); ++ if (err < 0) { ++ AP6211_ERR("wsec error %d\n", err); ++ return BCME_ERROR; ++ } ++ /* set upper-layer auth */ ++ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); ++ if (err < 0) { ++ AP6211_ERR("wpa_auth error %d\n", err); ++ return BCME_ERROR; ++ } ++exit: ++ return 0; ++} ++ ++static s32 ++wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx) ++{ ++ wpa_suite_mcast_t *mcast; ++ wpa_suite_ucast_t *ucast; ++ wpa_suite_auth_key_mgmt_t *mgmt; ++ u16 auth = 0; /* d11 open authentication */ ++ u16 count; ++ s32 err = BCME_OK; ++ s32 len = 0; ++ u32 i; ++ u32 wsec; ++ u32 pval = 0; ++ u32 gval = 0; ++ u32 wpa_auth = 0; ++ u32 tmp = 0; ++ ++ if (wpaie == NULL) ++ goto exit; ++ AP6211_DEBUG("Enter \n"); ++ len = wpaie->length; /* value length */ ++ len -= WPA_IE_TAG_FIXED_LEN; ++ /* check for multicast cipher suite */ ++ if (len < WPA_SUITE_LEN) { ++ AP6211_DEBUG("no multicast cipher suite\n"); ++ goto exit; ++ } ++ ++ /* pick up multicast cipher */ ++ mcast = (wpa_suite_mcast_t *)&wpaie[1]; ++ len -= WPA_SUITE_LEN; ++ if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) { ++ if (IS_WPA_CIPHER(mcast->type)) { ++ tmp = 0; ++ switch (mcast->type) { ++ case WPA_CIPHER_NONE: ++ tmp = 0; ++ break; ++ case WPA_CIPHER_WEP_40: ++ case WPA_CIPHER_WEP_104: ++ tmp = WEP_ENABLED; ++ break; ++ case WPA_CIPHER_TKIP: ++ tmp = TKIP_ENABLED; ++ break; ++ case WPA_CIPHER_AES_CCM: ++ tmp = AES_ENABLED; ++ break; ++ default: ++ AP6211_ERR("No Security Info\n"); ++ } ++ gval |= tmp; ++ } ++ } ++ /* Check for unicast suite(s) */ ++ if (len < WPA_IE_SUITE_COUNT_LEN) { ++ AP6211_DEBUG("no unicast suite\n"); ++ goto exit; ++ } ++ /* walk thru unicast cipher list and pick up what we recognize */ ++ ucast = (wpa_suite_ucast_t *)&mcast[1]; ++ count = ltoh16_ua(&ucast->count); ++ len -= WPA_IE_SUITE_COUNT_LEN; ++ for (i = 0; i < count && len >= WPA_SUITE_LEN; ++ i++, len -= WPA_SUITE_LEN) { ++ if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) { ++ if (IS_WPA_CIPHER(ucast->list[i].type)) { ++ tmp = 0; ++ switch (ucast->list[i].type) { ++ case WPA_CIPHER_NONE: ++ tmp = 0; ++ break; ++ case WPA_CIPHER_WEP_40: ++ case WPA_CIPHER_WEP_104: ++ tmp = WEP_ENABLED; ++ break; ++ case WPA_CIPHER_TKIP: ++ tmp = TKIP_ENABLED; ++ break; ++ case WPA_CIPHER_AES_CCM: ++ tmp = AES_ENABLED; ++ break; ++ default: ++ AP6211_ERR("No Security Info\n"); ++ } ++ pval |= tmp; ++ } ++ } ++ } ++ len -= (count - i) * WPA_SUITE_LEN; ++ /* Check for auth key management suite(s) */ ++ if (len < WPA_IE_SUITE_COUNT_LEN) { ++ AP6211_DEBUG(" no auth key mgmt suite\n"); ++ goto exit; ++ } ++ /* walk thru auth management suite list and pick up what we recognize */ ++ mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[count]; ++ count = ltoh16_ua(&mgmt->count); ++ len -= WPA_IE_SUITE_COUNT_LEN; ++ for (i = 0; i < count && len >= WPA_SUITE_LEN; ++ i++, len -= WPA_SUITE_LEN) { ++ if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) { ++ if (IS_WPA_AKM(mgmt->list[i].type)) { ++ tmp = 0; ++ switch (mgmt->list[i].type) { ++ case RSN_AKM_NONE: ++ tmp = WPA_AUTH_NONE; ++ break; ++ case RSN_AKM_UNSPECIFIED: ++ tmp = WPA_AUTH_UNSPECIFIED; ++ break; ++ case RSN_AKM_PSK: ++ tmp = WPA_AUTH_PSK; ++ break; ++ default: ++ AP6211_ERR("No Key Mgmt Info\n"); ++ } ++ wpa_auth |= tmp; ++ } ++ } ++ ++ } ++ /* FOR WPS , set SEC_OW_ENABLED */ ++ wsec = (pval | gval | SES_OW_ENABLED); ++ /* set auth */ ++ err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); ++ if (err < 0) { ++ AP6211_ERR("auth error %d\n", err); ++ return BCME_ERROR; ++ } ++ /* set wsec */ ++ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); ++ if (err < 0) { ++ AP6211_ERR("wsec error %d\n", err); ++ return BCME_ERROR; ++ } ++ /* set upper-layer auth */ ++ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); ++ if (err < 0) { ++ AP6211_ERR("wpa_auth error %d\n", err); ++ return BCME_ERROR; ++ } ++exit: ++ return 0; ++} ++ ++static s32 ++wl_cfg80211_bcn_validate_sec( ++ struct net_device *dev, ++ struct parsed_ies *ies, ++ u32 dev_role, ++ s32 bssidx) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ ++ if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) { ++ /* For P2P GO, the sec type is WPA2-PSK */ ++ AP6211_DEBUG("P2P GO: validating wpa2_ie"); ++ if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0) ++ return BCME_ERROR; ++ ++ } else if (dev_role == NL80211_IFTYPE_AP) { ++ ++ AP6211_DEBUG("SoftAP: validating security"); ++ /* If wpa2_ie or wpa_ie is present validate it */ ++ if ((ies->wpa2_ie || ies->wpa_ie) && ++ ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || ++ wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) { ++ wl->ap_info->security_mode = false; ++ return BCME_ERROR; ++ } ++ ++ wl->ap_info->security_mode = true; ++ if (wl->ap_info->rsn_ie) { ++ kfree(wl->ap_info->rsn_ie); ++ wl->ap_info->rsn_ie = NULL; ++ } ++ if (wl->ap_info->wpa_ie) { ++ kfree(wl->ap_info->wpa_ie); ++ wl->ap_info->wpa_ie = NULL; ++ } ++ if (wl->ap_info->wps_ie) { ++ kfree(wl->ap_info->wps_ie); ++ wl->ap_info->wps_ie = NULL; ++ } ++ if (ies->wpa_ie != NULL) { ++ /* WPAIE */ ++ wl->ap_info->rsn_ie = NULL; ++ wl->ap_info->wpa_ie = kmemdup(ies->wpa_ie, ++ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, ++ GFP_KERNEL); ++ } else if (ies->wpa2_ie != NULL) { ++ /* RSNIE */ ++ wl->ap_info->wpa_ie = NULL; ++ wl->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, ++ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, ++ GFP_KERNEL); ++ } ++ ++ if (!ies->wpa2_ie && !ies->wpa_ie) { ++ wl_validate_opensecurity(dev, bssidx); ++ wl->ap_info->security_mode = false; ++ } ++ ++ if (ies->wps_ie) { ++ wl->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); ++ } ++ } ++ ++ return 0; ++ ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) ++static s32 wl_cfg80211_bcn_set_params( ++ struct cfg80211_ap_settings *info, ++ struct net_device *dev, ++ u32 dev_role, s32 bssidx) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ s32 err = BCME_OK; ++ ++ AP6211_DEBUG("interval (%d) \ndtim_period (%d) \n", ++ info->beacon_interval, info->dtim_period); ++ ++ if (info->beacon_interval) { ++ if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, ++ &info->beacon_interval, sizeof(s32), true)) < 0) { ++ AP6211_ERR("Beacon Interval Set Error, %d\n", err); ++ return err; ++ } ++ } ++ ++ if (info->dtim_period) { ++ if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, ++ &info->dtim_period, sizeof(s32), true)) < 0) { ++ AP6211_ERR("DTIM Interval Set Error, %d\n", err); ++ return err; ++ } ++ } ++ ++ if ((info->ssid) && (info->ssid_len > 0) && ++ (info->ssid_len <= 32)) { ++ AP6211_DEBUG("SSID (%s) len:%d \n", info->ssid, info->ssid_len); ++ if (dev_role == NL80211_IFTYPE_AP) { ++ /* Store the hostapd SSID */ ++ memset(wl->hostapd_ssid.SSID, 0x00, 32); ++ memcpy(wl->hostapd_ssid.SSID, info->ssid, info->ssid_len); ++ wl->hostapd_ssid.SSID_len = info->ssid_len; ++ } else { ++ /* P2P GO */ ++ memset(wl->p2p->ssid.SSID, 0x00, 32); ++ memcpy(wl->p2p->ssid.SSID, info->ssid, info->ssid_len); ++ wl->p2p->ssid.SSID_len = info->ssid_len; ++ } ++ } ++ ++ if (info->hidden_ssid) { ++ if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0) ++ AP6211_ERR("failed to set hidden : %d\n", err); ++ AP6211_DEBUG("hidden_ssid_enum_val: %d \n", info->hidden_ssid); ++ } ++ ++ return err; ++} ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ ++ ++static s32 ++wl_cfg80211_parse_ies(u8 *ptr, u32 len, struct parsed_ies *ies) ++{ ++ s32 err = BCME_OK; ++ ++ memset(ies, 0, sizeof(struct parsed_ies)); ++ ++ /* find the WPSIE */ ++ if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) { ++ AP6211_DEBUG("WPSIE in beacon \n"); ++ ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN; ++ } else { ++ AP6211_ERR("No WPSIE in beacon \n"); ++ } ++ ++ /* find the RSN_IE */ ++ if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len, ++ DOT11_MNG_RSN_ID)) != NULL) { ++ AP6211_DEBUG(" WPA2 IE found\n"); ++ ies->wpa2_ie_len = ies->wpa2_ie->len; ++ } ++ ++ /* find the WPA_IE */ ++ if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) { ++ AP6211_DEBUG(" WPA found\n"); ++ ies->wpa_ie_len = ies->wpa_ie->length; ++ } ++ ++ return err; ++ ++} ++ ++static s32 ++wl_cfg80211_bcn_bringup_ap( ++ struct net_device *dev, ++ struct parsed_ies *ies, ++ u32 dev_role, s32 bssidx) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct wl_join_params join_params; ++ bool is_bssup = false; ++ s32 infra = 1; ++ s32 join_params_size = 0; ++ s32 ap = 1; ++ s32 err = BCME_OK; ++ ++ AP6211_DEBUG("Enter dev_role: %d\n", dev_role); ++ ++ /* Common code for SoftAP and P2P GO */ ++ wldev_iovar_setint(dev, "mpc", 0); ++ ++ if (dev_role == NL80211_IFTYPE_P2P_GO) { ++ is_bssup = wl_cfgp2p_bss_isup(dev, bssidx); ++ if (!is_bssup && (ies->wpa2_ie != NULL)) { ++ ++ err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); ++ if (err < 0) { ++ AP6211_ERR("SET INFRA error %d\n", err); ++ goto exit; ++ } ++ ++ err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p->ssid, ++ sizeof(wl->p2p->ssid), wl->ioctl_buf, WLC_IOCTL_MAXLEN, ++ bssidx, &wl->ioctl_buf_sync); ++ if (err < 0) { ++ AP6211_ERR("GO SSID setting error %d\n", err); ++ goto exit; ++ } ++ ++ if ((err = wl_cfgp2p_bss(wl, dev, bssidx, 1)) < 0) { ++ AP6211_ERR("GO Bring up error %d\n", err); ++ goto exit; ++ } ++ } else ++ AP6211_DEBUG("Bss is already up\n"); ++ } else if ((dev_role == NL80211_IFTYPE_AP) && ++ (wl_get_drv_status(wl, AP_CREATING, dev))) { ++ /* Device role SoftAP */ ++ err = wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true); ++ if (err < 0) { ++ AP6211_ERR("WLC_DOWN error %d\n", err); ++ goto exit; ++ } ++ err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); ++ if (err < 0) { ++ AP6211_ERR("SET INFRA error %d\n", err); ++ goto exit; ++ } ++ if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { ++ AP6211_ERR("setting AP mode failed %d \n", err); ++ goto exit; ++ } ++ ++ err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_UP error (%d)\n", err); ++ goto exit; ++ } ++ ++ memset(&join_params, 0, sizeof(join_params)); ++ /* join parameters starts with ssid */ ++ join_params_size = sizeof(join_params.ssid); ++ memcpy(join_params.ssid.SSID, wl->hostapd_ssid.SSID, ++ wl->hostapd_ssid.SSID_len); ++ join_params.ssid.SSID_len = htod32(wl->hostapd_ssid.SSID_len); ++ ++ /* create softap */ ++ if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, ++ join_params_size, true)) == 0) { ++ AP6211_DEBUG("SoftAP set SSID (%s) success\n", join_params.ssid.SSID); ++ wl_clr_drv_status(wl, AP_CREATING, dev); ++ wl_set_drv_status(wl, AP_CREATED, dev); ++ } ++ } ++ ++ ++exit: ++ return err; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) ++s32 ++wl_cfg80211_parse_set_ies( ++ struct net_device *dev, ++ struct cfg80211_beacon_data *info, ++ struct parsed_ies *ies, ++ u32 dev_role, ++ s32 bssidx) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct parsed_ies prb_ies; ++ s32 err = BCME_OK; ++ ++ memset(ies, 0, sizeof(struct parsed_ies)); ++ memset(&prb_ies, 0, sizeof(struct parsed_ies)); ++ ++ /* Parse Beacon IEs */ ++ if (wl_cfg80211_parse_ies((u8 *)info->tail, ++ info->tail_len, ies) < 0) { ++ AP6211_ERR("Beacon get IEs failed \n"); ++ err = -EINVAL; ++ goto fail; ++ } ++ ++ /* Set Beacon IEs to FW */ ++ if ((err = wl_cfgp2p_set_management_ie(wl, dev, bssidx, ++ VNDR_IE_BEACON_FLAG, (u8 *)info->tail, ++ info->tail_len)) < 0) { ++ AP6211_ERR("Set Beacon IE Failed \n"); ++ } else { ++ AP6211_DEBUG("Applied Vndr IEs for Beacon \n"); ++ } ++ ++ /* Parse Probe Response IEs */ ++ if (wl_cfg80211_parse_ies((u8 *)info->proberesp_ies, ++ info->proberesp_ies_len, &prb_ies) < 0) { ++ AP6211_ERR("PRB RESP get IEs failed \n"); ++ err = -EINVAL; ++ goto fail; ++ } ++ ++ /* Set Probe Response IEs to FW */ ++ if ((err = wl_cfgp2p_set_management_ie(wl, dev, bssidx, ++ VNDR_IE_PRBRSP_FLAG, (u8 *)info->proberesp_ies, ++ info->proberesp_ies_len)) < 0) { ++ AP6211_ERR("Set Probe Resp IE Failed \n"); ++ } else { ++ AP6211_DEBUG("Applied Vndr IEs for Probe Resp \n"); ++ } ++ ++fail: ++ ++ return err; ++} ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ ++ ++static s32 wl_cfg80211_hostapd_sec( ++ struct net_device *dev, ++ struct parsed_ies *ies, ++ s32 bssidx) ++{ ++ bool update_bss = 0; ++ struct wl_priv *wl = wlcfg_drv_priv; ++ ++ ++ if (ies->wps_ie) { ++ if (wl->ap_info->wps_ie && ++ memcmp(wl->ap_info->wps_ie, ies->wps_ie, ies->wps_ie_len)) { ++ AP6211_DEBUG(" WPS IE is changed\n"); ++ kfree(wl->ap_info->wps_ie); ++ wl->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); ++ } else if (wl->ap_info->wps_ie == NULL) { ++ AP6211_DEBUG(" WPS IE is added\n"); ++ wl->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); ++ } ++ if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) { ++ if (!wl->ap_info->security_mode) { ++ /* change from open mode to security mode */ ++ update_bss = true; ++ if (ies->wpa_ie != NULL) { ++ wl->ap_info->wpa_ie = kmemdup(ies->wpa_ie, ++ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, ++ GFP_KERNEL); ++ } else { ++ wl->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, ++ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, ++ GFP_KERNEL); ++ } ++ } else if (wl->ap_info->wpa_ie) { ++ /* change from WPA2 mode to WPA mode */ ++ if (ies->wpa_ie != NULL) { ++ update_bss = true; ++ kfree(wl->ap_info->rsn_ie); ++ wl->ap_info->rsn_ie = NULL; ++ wl->ap_info->wpa_ie = kmemdup(ies->wpa_ie, ++ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, ++ GFP_KERNEL); ++ } else if (memcmp(wl->ap_info->rsn_ie, ++ ies->wpa2_ie, ies->wpa2_ie->len ++ + WPA_RSN_IE_TAG_FIXED_LEN)) { ++ update_bss = true; ++ kfree(wl->ap_info->rsn_ie); ++ wl->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, ++ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, ++ GFP_KERNEL); ++ wl->ap_info->wpa_ie = NULL; ++ } ++ } ++ if (update_bss) { ++ wl->ap_info->security_mode = true; ++ wl_cfgp2p_bss(wl, dev, bssidx, 0); ++ if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || ++ wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) { ++ return BCME_ERROR; ++ } ++ wl_cfgp2p_bss(wl, dev, bssidx, 1); ++ } ++ } ++ } else { ++ AP6211_ERR("No WPSIE in beacon \n"); ++ } ++ return 0; ++} ++ ++#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ ++ 2, 0)) ++static s32 ++wl_cfg80211_del_station( ++ struct wiphy *wiphy, ++ struct net_device *ndev, ++ u8* mac_addr) ++{ ++ struct net_device *dev; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ scb_val_t scb_val; ++ s8 eabuf[ETHER_ADDR_STR_LEN]; ++ ++ AP6211_DEBUG("Entry\n"); ++ if (mac_addr == NULL) { ++ AP6211_DEBUG("mac_addr is NULL ignore it\n"); ++ return 0; ++ } ++ ++ if (ndev == wl->p2p_net) { ++ dev = wl_to_prmry_ndev(wl); ++ } else { ++ dev = ndev; ++ } ++ ++ if (p2p_is_on(wl)) { ++ /* Suspend P2P discovery search-listen to prevent it from changing the ++ * channel. ++ */ ++ if ((wl_cfgp2p_discover_enable_search(wl, false)) < 0) { ++ AP6211_ERR("Can not disable discovery mode\n"); ++ return -EFAULT; ++ } ++ } ++ ++ memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN); ++ scb_val.val = DOT11_RC_DEAUTH_LEAVING; ++ if (wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, ++ sizeof(scb_val_t), true)) ++ AP6211_ERR("WLC_SCB_DEAUTHENTICATE_FOR_REASON failed\n"); ++ AP6211_DEBUG("Disconnect STA : %s scb_val.val %d\n", ++ bcm_ether_ntoa((const struct ether_addr *)mac_addr, eabuf), ++ scb_val.val); ++ wl_delay(400); ++ return 0; ++} ++#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) ++static s32 ++wl_cfg80211_start_ap( ++ struct wiphy *wiphy, ++ struct net_device *dev, ++ struct cfg80211_ap_settings *info) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ s32 err = BCME_OK; ++ struct parsed_ies ies; ++ s32 bssidx = 0; ++ u32 dev_role = 0; ++ ++ AP6211_DEBUG("Enter \n"); ++ if (dev == wl_to_prmry_ndev(wl)) { ++ AP6211_DEBUG("Start AP req on primary iface: Softap\n"); ++ dev_role = NL80211_IFTYPE_AP; ++ } else if (dev == wl->p2p_net) { ++ /* Group Add request on p2p0 */ ++ AP6211_DEBUG("Start AP req on P2P iface: GO\n"); ++ dev = wl_to_prmry_ndev(wl); ++ dev_role = NL80211_IFTYPE_P2P_GO; ++ } ++ ++ bssidx = wl_cfgp2p_find_idx(wl, dev); ++ if (p2p_is_on(wl) && ++ (bssidx == wl_to_p2p_bss_bssidx(wl, ++ P2PAPI_BSSCFG_CONNECTION))) { ++ dev_role = NL80211_IFTYPE_P2P_GO; ++ AP6211_DEBUG("Start AP req on P2P connection iface\n"); ++ } ++ ++ if ((err = wl_cfg80211_bcn_set_params(info, dev, ++ dev_role, bssidx)) < 0) { ++ AP6211_ERR("Beacon params set failed \n"); ++ goto fail; ++ } ++ ++ /* Set IEs to FW */ ++ if ((err = wl_cfg80211_parse_set_ies(dev, &info->beacon, ++ &ies, dev_role, bssidx) < 0)) { ++ AP6211_ERR("Set IEs failed \n"); ++ goto fail; ++ } ++ ++ if ((wl_cfg80211_bcn_validate_sec(dev, &ies, ++ dev_role, bssidx)) < 0) ++ { ++ AP6211_ERR("Beacon set security failed \n"); ++ goto fail; ++ } ++ ++ if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies, ++ dev_role, bssidx)) < 0) { ++ AP6211_ERR("Beacon bring up AP/GO failed \n"); ++ goto fail; ++ } ++ ++ AP6211_DEBUG("** AP/GO Created **\n"); ++ ++fail: ++ if (err) { ++ AP6211_ERR("ADD/SET beacon failed\n"); ++ wldev_iovar_setint(dev, "mpc", 1); ++ } ++ ++ return err; ++} ++ ++static s32 ++wl_cfg80211_stop_ap( ++ struct wiphy *wiphy, ++ struct net_device *dev) ++{ ++ int err = 0; ++ u32 dev_role = 0; ++ int infra = 0; ++ int ap = 0; ++ s32 bssidx = 0; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ ++ AP6211_DEBUG("Enter \n"); ++ if (dev == wl_to_prmry_ndev(wl)) { ++ dev_role = NL80211_IFTYPE_AP; ++ } else if (dev == wl->p2p_net) { ++ /* Group Add request on p2p0 */ ++ dev = wl_to_prmry_ndev(wl); ++ dev_role = NL80211_IFTYPE_P2P_GO; ++ } ++ bssidx = wl_cfgp2p_find_idx(wl, dev); ++ if (p2p_is_on(wl) && ++ (bssidx == wl_to_p2p_bss_bssidx(wl, ++ P2PAPI_BSSCFG_CONNECTION))) { ++ dev_role = NL80211_IFTYPE_P2P_GO; ++ } ++ ++ if (dev_role == NL80211_IFTYPE_AP) { ++ /* SoftAp on primary Interface. ++ * Shut down AP and turn on MPC ++ */ ++ err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); ++ if (err < 0) { ++ AP6211_ERR("SET INFRA error %d\n", err); ++ err = -ENOTSUPP; ++ goto exit; ++ } ++ if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { ++ AP6211_ERR("setting AP mode failed %d \n", err); ++ err = -ENOTSUPP; ++ goto exit; ++ } ++ ++ err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_UP error (%d)\n", err); ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ wl_clr_drv_status(wl, AP_CREATED, dev); ++ /* Turn on the MPC */ ++ wldev_iovar_setint(dev, "mpc", 1); ++ } else { ++ AP6211_DEBUG("Stopping P2P GO \n"); ++ } ++ ++exit: ++ return err; ++} ++ ++static s32 ++wl_cfg80211_change_beacon( ++ struct wiphy *wiphy, ++ struct net_device *dev, ++ struct cfg80211_beacon_data *info) ++{ ++ s32 err = BCME_OK; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct parsed_ies ies; ++ u32 dev_role = 0; ++ s32 bssidx = 0; ++ ++ AP6211_DEBUG("Enter \n"); ++ ++ if (dev == wl_to_prmry_ndev(wl)) { ++ dev_role = NL80211_IFTYPE_AP; ++ } else if (dev == wl->p2p_net) { ++ /* Group Add request on p2p0 */ ++ dev = wl_to_prmry_ndev(wl); ++ dev_role = NL80211_IFTYPE_P2P_GO; ++ } ++ ++ bssidx = wl_cfgp2p_find_idx(wl, dev); ++ if (p2p_is_on(wl) && ++ (bssidx == wl_to_p2p_bss_bssidx(wl, ++ P2PAPI_BSSCFG_CONNECTION))) { ++ dev_role = NL80211_IFTYPE_P2P_GO; ++ } ++ ++ /* Set IEs to FW */ ++ if ((err = wl_cfg80211_parse_set_ies(dev, info, ++ &ies, dev_role, bssidx) < 0)) { ++ AP6211_ERR("Set IEs failed \n"); ++ goto fail; ++ } ++ ++ if (dev_role == NL80211_IFTYPE_AP) { ++ if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) { ++ AP6211_ERR("Hostapd update sec failed \n"); ++ err = -EINVAL; ++ goto fail; ++ } ++ } ++ ++fail: ++ return err; ++} ++#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ ++static s32 ++wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, ++ struct beacon_parameters *info) ++{ ++ s32 err = BCME_OK; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ s32 ie_offset = 0; ++ s32 bssidx = 0; ++ u32 dev_role = NL80211_IFTYPE_AP; ++ struct parsed_ies ies; ++ bcm_tlv_t *ssid_ie; ++ bool pbc = 0; ++ ++ AP6211_DEBUG("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n", ++ info->interval, info->dtim_period, info->head_len, info->tail_len); ++ ++ if (dev == wl_to_prmry_ndev(wl)) { ++ dev_role = NL80211_IFTYPE_AP; ++ } else if (dev == wl->p2p_net) { ++ /* Group Add request on p2p0 */ ++ dev = wl_to_prmry_ndev(wl); ++ dev_role = NL80211_IFTYPE_P2P_GO; ++ } ++ ++ bssidx = wl_cfgp2p_find_idx(wl, dev); ++ if (p2p_is_on(wl) && ++ (bssidx == wl_to_p2p_bss_bssidx(wl, ++ P2PAPI_BSSCFG_CONNECTION))) { ++ dev_role = NL80211_IFTYPE_P2P_GO; ++ } ++ ++ ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; ++ /* find the SSID */ ++ if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset], ++ info->head_len - ie_offset, ++ DOT11_MNG_SSID_ID)) != NULL) { ++ if (dev_role == NL80211_IFTYPE_AP) { ++ /* Store the hostapd SSID */ ++ memset(&wl->hostapd_ssid.SSID[0], 0x00, 32); ++ memcpy(&wl->hostapd_ssid.SSID[0], ssid_ie->data, ssid_ie->len); ++ wl->hostapd_ssid.SSID_len = ssid_ie->len; ++ } else { ++ /* P2P GO */ ++ memset(&wl->p2p->ssid.SSID[0], 0x00, 32); ++ memcpy(wl->p2p->ssid.SSID, ssid_ie->data, ssid_ie->len); ++ wl->p2p->ssid.SSID_len = ssid_ie->len; ++ } ++ } ++ ++ if (wl_cfg80211_parse_ies((u8 *)info->tail, ++ info->tail_len, &ies) < 0) { ++ AP6211_ERR("Beacon get IEs failed \n"); ++ err = -EINVAL; ++ goto fail; ++ } ++ ++ if (wl_cfgp2p_set_management_ie(wl, dev, bssidx, ++ VNDR_IE_BEACON_FLAG, (u8 *)info->tail, ++ info->tail_len) < 0) { ++ AP6211_ERR("Beacon set IEs failed \n"); ++ goto fail; ++ } else { ++ AP6211_DEBUG("Applied Vndr IEs for Beacon \n"); ++ } ++ if (!wl_cfgp2p_bss_isup(dev, bssidx) && ++ (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx) < 0)) ++ { ++ AP6211_ERR("Beacon set security failed \n"); ++ goto fail; ++ } ++ ++ /* Set BI and DTIM period */ ++ if (info->interval) { ++ if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, ++ &info->interval, sizeof(s32), true)) < 0) { ++ AP6211_ERR("Beacon Interval Set Error, %d\n", err); ++ return err; ++ } ++ } ++ if (info->dtim_period) { ++ if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, ++ &info->dtim_period, sizeof(s32), true)) < 0) { ++ AP6211_ERR("DTIM Interval Set Error, %d\n", err); ++ return err; ++ } ++ } ++ ++ if (wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx) < 0) { ++ AP6211_ERR("Beacon bring up AP/GO failed \n"); ++ goto fail; ++ } ++ ++ if (wl_get_drv_status(wl, AP_CREATED, dev)) { ++ /* Soft AP already running. Update changed params */ ++ if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) { ++ AP6211_ERR("Hostapd update sec failed \n"); ++ err = -EINVAL; ++ goto fail; ++ } ++ } ++ ++ /* Enable Probe Req filter */ ++ if (((dev_role == NL80211_IFTYPE_P2P_GO) || ++ (dev_role == NL80211_IFTYPE_AP)) && (ies.wps_ie != NULL)) { ++ wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc); ++ if (pbc) ++ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); ++ } ++ ++ AP6211_DEBUG("** ADD/SET beacon done **\n"); ++ ++fail: ++ if (err) { ++ AP6211_ERR("ADD/SET beacon failed\n"); ++ wldev_iovar_setint(dev, "mpc", 1); ++ } ++ return err; ++ ++} ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ ++ ++#ifdef WL_SCHED_SCAN ++#define PNO_TIME 30 ++#define PNO_REPEAT 4 ++#define PNO_FREQ_EXPO_MAX 2 ++int wl_cfg80211_sched_scan_start(struct wiphy *wiphy, ++ struct net_device *dev, ++ struct cfg80211_sched_scan_request *request) ++{ ++ ushort pno_time = PNO_TIME; ++ int pno_repeat = PNO_REPEAT; ++ int pno_freq_expo_max = PNO_FREQ_EXPO_MAX; ++ wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ struct cfg80211_ssid *ssid = NULL; ++ int ssid_count = 0; ++ int i; ++ int ret = 0; ++ ++ AP6211_DEBUG("Enter \n"); ++ AP6211_DEBUG(">>> SCHED SCAN START\n"); ++ AP6211_DEBUG("Enter n_match_sets:%d n_ssids:%d \n", ++ request->n_match_sets, request->n_ssids); ++ AP6211_DEBUG("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n", ++ request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max); ++ ++ ++ if (!request || !request->n_ssids || !request->n_match_sets) { ++ AP6211_ERR("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids); ++ return -EINVAL; ++ } ++ ++ memset(&ssids_local, 0, sizeof(ssids_local)); ++ ++ if (request->n_match_sets > 0) { ++ for (i = 0; i < request->n_match_sets; i++) { ++ ssid = &request->match_sets[i].ssid; ++ memcpy(ssids_local[i].SSID, ssid->ssid, ssid->ssid_len); ++ ssids_local[i].SSID_len = ssid->ssid_len; ++ AP6211_DEBUG(">>> PNO filter set for ssid (%s) \n", ssid->ssid); ++ ssid_count++; ++ } ++ } ++ ++ if (request->n_ssids > 0) { ++ for (i = 0; i < request->n_ssids; i++) { ++ /* Active scan req for ssids */ ++ AP6211_DEBUG(">>> Active scan req for ssid (%s) \n", request->ssids[i].ssid); ++ ++ /* match_set ssids is a supert set of n_ssid list, so we need ++ * not add these set seperately ++ */ ++ } ++ } ++ ++ if (ssid_count) { ++ if ((ret = dhd_dev_pno_set(dev, ssids_local, request->n_match_sets, ++ pno_time, pno_repeat, pno_freq_expo_max)) < 0) { ++ AP6211_ERR("PNO setup failed!! ret=%d \n", ret); ++ return -EINVAL; ++ } ++ ++ /* Enable the PNO */ ++ if (dhd_dev_pno_enable(dev, 1) < 0) { ++ AP6211_ERR("PNO enable failed!! ret=%d \n", ret); ++ return -EINVAL; ++ } ++ wl->sched_scan_req = request; ++ } else { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) ++{ ++ struct wl_priv *wl = wiphy_priv(wiphy); ++ ++ AP6211_DEBUG("Enter \n"); ++ AP6211_DEBUG(">>> SCHED SCAN STOP\n"); ++ ++ if (dhd_dev_pno_enable(dev, 0) < 0) ++ AP6211_ERR("PNO disable failed"); ++ ++ if (dhd_dev_pno_reset(dev) < 0) ++ AP6211_ERR("PNO reset failed"); ++ ++ if (wl->scan_request && wl->sched_scan_running) { ++ AP6211_DEBUG(">>> Sched scan running. Aborting it..\n"); ++ wl_notify_escan_complete(wl, dev, true, true); ++ } ++ ++ wl->sched_scan_req = NULL; ++ wl->sched_scan_running = FALSE; ++ ++ return 0; ++} ++#endif /* WL_SCHED_SCAN */ ++ ++static struct cfg80211_ops wl_cfg80211_ops = { ++ .add_virtual_intf = wl_cfg80211_add_virtual_iface, ++ .del_virtual_intf = wl_cfg80211_del_virtual_iface, ++ .change_virtual_intf = wl_cfg80211_change_virtual_iface, ++ .scan = wl_cfg80211_scan, ++ .set_wiphy_params = wl_cfg80211_set_wiphy_params, ++ .join_ibss = wl_cfg80211_join_ibss, ++ .leave_ibss = wl_cfg80211_leave_ibss, ++ .get_station = wl_cfg80211_get_station, ++ .set_tx_power = wl_cfg80211_set_tx_power, ++ .get_tx_power = wl_cfg80211_get_tx_power, ++ .add_key = wl_cfg80211_add_key, ++ .del_key = wl_cfg80211_del_key, ++ .get_key = wl_cfg80211_get_key, ++ .set_default_key = wl_cfg80211_config_default_key, ++ .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key, ++ .set_power_mgmt = wl_cfg80211_set_power_mgmt, ++ .connect = wl_cfg80211_connect, ++ .disconnect = wl_cfg80211_disconnect, ++ .suspend = wl_cfg80211_suspend, ++ .resume = wl_cfg80211_resume, ++ .set_pmksa = wl_cfg80211_set_pmksa, ++ .del_pmksa = wl_cfg80211_del_pmksa, ++ .flush_pmksa = wl_cfg80211_flush_pmksa, ++ .remain_on_channel = wl_cfg80211_remain_on_channel, ++ .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel, ++ .mgmt_tx = wl_cfg80211_mgmt_tx, ++ .mgmt_frame_register = wl_cfg80211_mgmt_frame_register, ++ .change_bss = wl_cfg80211_change_bss, ++ .set_channel = wl_cfg80211_set_channel, ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) ++ .set_beacon = wl_cfg80211_add_set_beacon, ++ .add_beacon = wl_cfg80211_add_set_beacon, ++#else ++ .change_beacon = wl_cfg80211_change_beacon, ++ .start_ap = wl_cfg80211_start_ap, ++ .stop_ap = wl_cfg80211_stop_ap, ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ ++#ifdef WL_SCHED_SCAN ++ .sched_scan_start = wl_cfg80211_sched_scan_start, ++ .sched_scan_stop = wl_cfg80211_sched_scan_stop, ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ ++#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ ++ 2, 0)) ++ .del_station = wl_cfg80211_del_station, ++ .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait, ++#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */ ++}; ++ ++s32 wl_mode_to_nl80211_iftype(s32 mode) ++{ ++ s32 err = 0; ++ ++ switch (mode) { ++ case WL_MODE_BSS: ++ return NL80211_IFTYPE_STATION; ++ case WL_MODE_IBSS: ++ return NL80211_IFTYPE_ADHOC; ++ case WL_MODE_AP: ++ return NL80211_IFTYPE_AP; ++ default: ++ return NL80211_IFTYPE_UNSPECIFIED; ++ } ++ ++ return err; ++} ++ ++static int ++wl_cfg80211_reg_notifier( ++ struct wiphy *wiphy, ++ struct regulatory_request *request) ++{ ++ struct wl_priv *wl = (struct wl_priv *)wiphy_priv(wiphy); ++ wl_country_t cspec = {{0}, 0, {0} }; ++ int ret = 0; ++ ++ if (!request || !wl) { ++ AP6211_ERR("Invalid arg\n"); ++ return -EINVAL; ++ } ++ ++ AP6211_DEBUG("ccode: %c%c Initiator: %d\n", ++ request->alpha2[0], request->alpha2[1], request->initiator); ++ ++ /* We support only REGDOM_SET_BY_USER as of now */ ++ if (request->initiator != NL80211_REGDOM_SET_BY_USER) { ++ AP6211_ERR("reg_notifier for intiator:%d not supported \n", ++ request->initiator); ++ return -ENOTSUPP; ++ } ++ ++ if (request->alpha2[0] == '0' && request->alpha2[1] == '0') { ++ /* world domain */ ++ AP6211_ERR("World domain. Setting XY/4 \n"); ++ strncpy(cspec.country_abbrev, "XY", strlen("XY")); ++ cspec.rev = 4; ++ } else { ++ memcpy(cspec.country_abbrev, request->alpha2, 2); ++ cspec.country_abbrev[3] = '\0'; ++ cspec.rev = -1; /* Unspecified */ ++ } ++ ++ if ((ret = wldev_iovar_setbuf(wl_to_prmry_ndev(wl), "country", (char *)&cspec, ++ sizeof(cspec), wl->ioctl_buf, WLC_IOCTL_SMLEN, NULL)) < 0) { ++ AP6211_ERR("set country Failed :%d\n", ret); ++ goto exit; ++ } ++ ++ if ((ret = wl_update_wiphybands(wl, false)) < 0) { ++ AP6211_ERR("wl_update_wiphybands failed\n"); ++ goto exit; ++ } ++ ++ AP6211_DEBUG("%s: set country '%s/%d' done\n", ++ __FUNCTION__, cspec.country_abbrev, cspec.rev); ++ ++exit: ++ return ret; ++} ++ ++static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev) ++{ ++ s32 err = 0; ++ wdev->wiphy = ++ wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv)); ++ if (unlikely(!wdev->wiphy)) { ++ AP6211_ERR("Couldn not allocate wiphy device\n"); ++ err = -ENOMEM; ++ return err; ++ } ++ set_wiphy_dev(wdev->wiphy, sdiofunc_dev); ++ wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX; ++ /* Report how many SSIDs Driver can support per Scan request */ ++ wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX; ++ wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; ++#ifdef WL_SCHED_SCAN ++ wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT; ++ wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT; ++ wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX; ++ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; ++#endif /* WL_SCHED_SCAN */ ++ wdev->wiphy->interface_modes = ++ BIT(NL80211_IFTYPE_STATION) ++#if !(defined(WLP2P) && defined(WL_ENABLE_P2P_IF)) ++ | BIT(NL80211_IFTYPE_MONITOR) ++#endif ++ | BIT(NL80211_IFTYPE_AP); ++ ++ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; ++ ++ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; ++ wdev->wiphy->cipher_suites = __wl_cipher_suites; ++ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); ++ wdev->wiphy->max_remain_on_channel_duration = 5000; ++ wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes; ++#ifndef WL_POWERSAVE_DISABLED ++ wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; ++#else ++ wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; ++#endif /* !WL_POWERSAVE_DISABLED */ ++ wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK | ++ WIPHY_FLAG_4ADDR_AP | ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39) ++ WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS | ++#endif ++ WIPHY_FLAG_4ADDR_STATION; ++ /* If driver advertises FW_ROAM, the supplicant wouldn't ++ * send the BSSID & Freq in the connect command allowing the ++ * the driver to choose the AP to connect to. But unless we ++ * support ROAM_CACHE in firware this will delay the ASSOC as ++ * as the FW need to do a full scan before attempting to connect ++ * So that feature will just increase assoc. The better approach ++ * to let Supplicant to provide channel info and FW letter may roam ++ * if needed so DON'T advertise that featur eto Supplicant. ++ */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) ++ /* wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; */ ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) ++ wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | ++ WIPHY_FLAG_OFFCHAN_TX; ++#endif ++#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ ++ 4, 0)) ++ /* From 3.4 kernel ownards AP_SME flag can be advertised ++ * to remove the patch from supplicant ++ */ ++ wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME; ++#endif ++ ++ wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier; ++ ++ AP6211_DEBUG("Registering custom regulatory)\n"); ++ wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; ++ wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom); ++ /* Now we can register wiphy with cfg80211 module */ ++ err = wiphy_register(wdev->wiphy); ++ if (unlikely(err < 0)) { ++ AP6211_ERR("Couldn not register wiphy device (%d)\n", err); ++ wiphy_free(wdev->wiphy); ++ } ++ return err; ++} ++ ++static void wl_free_wdev(struct wl_priv *wl) ++{ ++ struct wireless_dev *wdev = wl->wdev; ++ struct wiphy *wiphy; ++ if (!wdev) { ++ AP6211_ERR("wdev is invalid\n"); ++ return; ++ } ++ wiphy = wdev->wiphy; ++ wiphy_unregister(wdev->wiphy); ++ wdev->wiphy->dev.parent = NULL; ++ ++ wl_delete_all_netinfo(wl); ++ wiphy_free(wiphy); ++ /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "wl", ++ * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!! ++ */ ++} ++ ++#if defined(RSSIAVG) ++static wl_rssi_cache_ctrl_t g_rssi_cache_ctrl; ++#endif ++#if defined(BSSCACHE) ++static wl_bss_cache_ctrl_t g_bss_cache_ctrl; ++#endif ++ ++static s32 wl_inform_bss(struct wl_priv *wl) ++{ ++ struct wl_scan_results *bss_list; ++ struct wl_bss_info *bi = NULL; /* must be initialized */ ++ s32 err = 0; ++ s32 i; ++#if defined(RSSIAVG) ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++#endif ++#if defined(BSSCACHE) ++ wl_bss_cache_t *node; ++#endif ++ ++ bss_list = wl->bss_list; ++#if defined(BSSCACHE) ++ if (g_bss_cache_ctrl.m_timer_expired || (p2p_is_on(wl) && p2p_scan(wl))) { ++#if defined(RSSIAVG) ++ wl_free_rssi_cache(&g_rssi_cache_ctrl); ++#endif ++ wl_free_bss_cache(&g_bss_cache_ctrl); ++ g_bss_cache_ctrl.m_timer_expired ^= 1; ++ } ++ wl_update_bss_cache(&g_bss_cache_ctrl, bss_list); ++ wl_delete_dirty_bss_cache(&g_bss_cache_ctrl); ++ wl_reset_bss_cache(&g_bss_cache_ctrl); ++#endif ++ ++#if defined(RSSIAVG) ++#if defined(BSSCACHE) ++ node = g_bss_cache_ctrl.m_cache_head; ++ for (;node;) { ++ wl_update_rssi_cache(&g_rssi_cache_ctrl, &node->results); ++ node = node->next; ++ } ++#else ++ wl_update_rssi_cache(&g_rssi_cache_ctrl, bss_list); ++#endif ++ if (!in_atomic()) ++ wl_update_connected_rssi_cache(&g_rssi_cache_ctrl, ndev); ++ wl_delete_dirty_rssi_cache(&g_rssi_cache_ctrl); ++ wl_reset_rssi_cache(&g_rssi_cache_ctrl); ++#endif ++ ++ AP6211_DEBUG("scanned AP count (%d)\n", bss_list->count); ++ ++#if defined(BSSCACHE) ++ node = g_bss_cache_ctrl.m_cache_head; ++ for (i=0; node && iresults.bss_info; ++ err = wl_inform_single_bss(wl, bi, 0); ++ if (unlikely(err)) ++ break; ++ node = node->next; ++ } ++ wl_run_bss_cache_timer(&g_bss_cache_ctrl, 0); ++ wl_run_bss_cache_timer(&g_bss_cache_ctrl, 1); ++#else ++ bi = next_bss(bss_list, bi); ++ for_each_bss(bss_list, bi, i) { ++ err = wl_inform_single_bss(wl, bi, 0); ++ if (unlikely(err)) ++ break; ++ } ++#endif ++ return err; ++} ++ ++static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 is_roam_done) ++{ ++ struct wiphy *wiphy = wl_to_wiphy(wl); ++ struct ieee80211_mgmt *mgmt; ++ struct ieee80211_channel *channel; ++ struct ieee80211_supported_band *band; ++ struct wl_cfg80211_bss_info *notif_bss_info; ++ struct wl_scan_req *sr = wl_to_sr(wl); ++ struct beacon_proberesp *beacon_proberesp; ++ struct cfg80211_bss *cbss = NULL; ++ s32 mgmt_type; ++ s32 signal; ++ u32 freq; ++ s32 err = 0; ++ gfp_t aflags; ++ u8 *ie_offset = NULL; ++ ++ if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) { ++ AP6211_DEBUG("Beacon is larger than buffer. Discarding\n"); ++ return err; ++ } ++ aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; ++ notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt) ++ - sizeof(u8) + WL_BSS_INFO_MAX, aflags); ++ if (unlikely(!notif_bss_info)) { ++ AP6211_ERR("notif_bss_info alloc failed\n"); ++ return -ENOMEM; ++ } ++ mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf; ++ notif_bss_info->channel = ++ bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(wl_chspec_driver_to_host(bi->chanspec)); ++ ++ if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL) ++ band = wiphy->bands[IEEE80211_BAND_2GHZ]; ++ else ++ band = wiphy->bands[IEEE80211_BAND_5GHZ]; ++ if (!band) { ++ AP6211_ERR("No valid band"); ++ kfree(notif_bss_info); ++ return -EINVAL; ++ } ++ notif_bss_info->rssi = dtoh16(bi->RSSI); ++#if defined(RSSIAVG) ++ notif_bss_info->rssi = wl_get_avg_rssi(&g_rssi_cache_ctrl, &bi->BSSID); ++#endif ++#if defined(RSSIOFFSET) ++ notif_bss_info->rssi = wl_update_rssi_offset(notif_bss_info->rssi); ++#endif ++ memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN); ++ mgmt_type = wl->active_scan ? ++ IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON; ++ if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) { ++ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type); ++ } ++ beacon_proberesp = wl->active_scan ? ++ (struct beacon_proberesp *)&mgmt->u.probe_resp : ++ (struct beacon_proberesp *)&mgmt->u.beacon; ++ beacon_proberesp->timestamp = 0; ++ beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period); ++ beacon_proberesp->capab_info = cpu_to_le16(bi->capability); ++ wl_rst_ie(wl); ++ ++ ie_offset = ((u8 *) bi) + bi->ie_offset; ++ ++ if (is_roam_done && ((int)(*(ie_offset)) == WLAN_EID_SSID && ++ ((int)(*(ie_offset+1)) == 0 || (int)(*(ie_offset+2)) == 0))) { ++ u8 *ie_new_offset = NULL; ++ uint8 ie_new_length; ++ ++ AP6211_ERR("WAR trace: Changing the SSID Info, from beacon %d\n", ++ bi->flags & WL_BSS_FLAGS_FROM_BEACON); ++ ++ ie_new_offset = (u8 *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); ++ if (ie_new_offset) { ++ *(ie_new_offset) = WLAN_EID_SSID; ++ *(ie_new_offset+1) = bi->SSID_len; ++ memcpy(ie_new_offset+2, bi->SSID, bi->SSID_len); ++ ie_new_length = bi->ie_length - *(ie_offset+1) + bi->SSID_len; ++ ++ /* Copy the remaining IE apart from SSID IE from bi */ ++ memcpy(ie_new_offset+2 + bi->SSID_len, ++ ie_offset+2 + *(ie_offset+1), ++ bi->ie_length - 2 - *(ie_offset+1)); ++ wl_mrg_ie(wl, ie_new_offset, ie_new_length); ++ kfree(ie_new_offset); ++ } else { ++ wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length); ++ } ++ } else { ++ wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length); ++ } ++ ++ wl_cp_ie(wl, beacon_proberesp->variable, WL_BSS_INFO_MAX - ++ offsetof(struct wl_cfg80211_bss_info, frame_buf)); ++ notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt, ++ u.beacon.variable) + wl_get_ielen(wl); ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) ++ freq = ieee80211_channel_to_frequency(notif_bss_info->channel); ++ (void)band->band; ++#else ++ freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band); ++#endif ++ if (freq == 0) { ++ AP6211_ERR("Invalid channel, fail to chcnage channel to freq\n"); ++ kfree(notif_bss_info); ++ return -EINVAL; ++ } ++ channel = ieee80211_get_channel(wiphy, freq); ++ if (unlikely(!channel)) { ++ AP6211_ERR("ieee80211_get_channel error\n"); ++ kfree(notif_bss_info); ++ return -EINVAL; ++ } ++ AP6211_DEBUG("BSSID %pM, channel %d, rssi %d, capability 0x04%x, mgmt_type %d, " ++ "frame_len %d, SSID \"%s\"\n", &bi->BSSID, notif_bss_info->channel, ++ notif_bss_info->rssi, mgmt->u.beacon.capab_info, mgmt_type, ++ notif_bss_info->frame_len, bi->SSID); ++ ++ signal = notif_bss_info->rssi * 100; ++ if (!mgmt->u.probe_resp.timestamp) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) ++ struct timespec ts; ++ get_monotonic_boottime(&ts); ++ mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000) ++ + ts.tv_nsec / 1000; ++#else ++ struct timeval tv; ++ do_gettimeofday(&tv); ++ mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec*1000000) ++ + tv.tv_usec; ++#endif ++ } ++ ++ cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt, ++ le16_to_cpu(notif_bss_info->frame_len), signal, aflags); ++ if (unlikely(!cbss)) { ++ AP6211_ERR("cfg80211_inform_bss_frame error\n"); ++ kfree(notif_bss_info); ++ return -EINVAL; ++ } ++ ++ cfg80211_put_bss(cbss); ++ kfree(notif_bss_info); ++ return err; ++} ++ ++static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev) ++{ ++ u32 event = ntoh32(e->event_type); ++ u32 status = ntoh32(e->status); ++ u16 flags = ntoh16(e->flags); ++ ++ AP6211_DEBUG("event %d, status %d flags %x\n", event, status, flags); ++ if (event == WLC_E_SET_SSID) { ++ if (status == WLC_E_STATUS_SUCCESS) { ++ if (!wl_is_ibssmode(wl, ndev)) ++ return true; ++ } ++ } else if (event == WLC_E_LINK) { ++ if (flags & WLC_EVENT_MSG_LINK) ++ return true; ++ } ++ ++ AP6211_DEBUG("wl_is_linkup false\n"); ++ return false; ++} ++ ++static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e) ++{ ++ u32 event = ntoh32(e->event_type); ++ u16 flags = ntoh16(e->flags); ++ ++ if (event == WLC_E_DEAUTH_IND || ++ event == WLC_E_DISASSOC_IND || ++ event == WLC_E_DISASSOC || ++ event == WLC_E_DEAUTH) { ++#if (WL_DBG_LEVEL > 0) ++ AP6211_ERR("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event]); ++#endif /* (WL_DBG_LEVEL > 0) */ ++ return true; ++ } else if (event == WLC_E_LINK) { ++ if (!(flags & WLC_EVENT_MSG_LINK)) { ++#if (WL_DBG_LEVEL > 0) ++ AP6211_ERR("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event]); ++#endif /* (WL_DBG_LEVEL > 0) */ ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e) ++{ ++ u32 event = ntoh32(e->event_type); ++ u32 status = ntoh32(e->status); ++ ++ if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS) ++ return true; ++ if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) ++ return true; ++ ++ return false; ++} ++ ++/* The mainline kernel >= 3.2.0 has support for indicating new/del station ++ * to AP/P2P GO via events. If this change is backported to kernel for which ++ * this driver is being built, then define WL_CFG80211_STA_EVENT. You ++ * should use this new/del sta event mechanism for BRCM supplicant >= 22. ++ */ ++static s32 ++wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ s32 err = 0; ++ u32 event = ntoh32(e->event_type); ++ u32 reason = ntoh32(e->reason); ++ u32 len = ntoh32(e->datalen); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) ++ bool isfree = false; ++ u8 *mgmt_frame; ++ u8 bsscfgidx = e->bsscfgidx; ++ s32 freq; ++ s32 channel; ++ u8 *body = NULL; ++ u16 fc = 0; ++ ++ struct ieee80211_supported_band *band; ++ struct ether_addr da; ++ struct ether_addr bssid; ++ struct wiphy *wiphy = wl_to_wiphy(wl); ++ channel_info_t ci; ++#else ++ struct station_info sinfo; ++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !WL_CFG80211_STA_EVENT */ ++ ++ AP6211_DEBUG("event %d status %d reason %d\n", event, ntoh32(e->status), reason); ++ /* if link down, bsscfg is disabled. */ ++ if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS && ++ wl_get_p2p_status(wl, IF_DELETING) && (ndev != wl_to_prmry_ndev(wl))) { ++ wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false); ++ AP6211_DEBUG("AP mode link down !! \n"); ++ complete(&wl->iface_disable); ++ return 0; ++ } ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) ++ AP6211_DEBUG("Enter \n"); ++ if (!len && (event == WLC_E_DEAUTH)) { ++ len = 2; /* reason code field */ ++ data = &reason; ++ } ++ if (len) { ++ body = kzalloc(len, GFP_KERNEL); ++ ++ if (body == NULL) { ++ AP6211_ERR("wl_notify_connect_status: Failed to allocate body\n"); ++ return WL_INVALID; ++ } ++ } ++ memset(&bssid, 0, ETHER_ADDR_LEN); ++ AP6211_DEBUG("Enter event %d ndev %p\n", event, ndev); ++ if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID) { ++ kfree(body); ++ return WL_INVALID; ++ } ++ if (len) ++ memcpy(body, data, len); ++ ++ wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", ++ NULL, 0, wl->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &wl->ioctl_buf_sync); ++ memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN); ++ err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); ++ switch (event) { ++ case WLC_E_ASSOC_IND: ++ fc = FC_ASSOC_REQ; ++ break; ++ case WLC_E_REASSOC_IND: ++ fc = FC_REASSOC_REQ; ++ break; ++ case WLC_E_DISASSOC_IND: ++ fc = FC_DISASSOC; ++ break; ++ case WLC_E_DEAUTH_IND: ++ fc = FC_DISASSOC; ++ break; ++ case WLC_E_DEAUTH: ++ fc = FC_DISASSOC; ++ break; ++ default: ++ fc = 0; ++ goto exit; ++ } ++ if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) { ++ kfree(body); ++ return err; ++ } ++ ++ channel = dtoh32(ci.hw_channel); ++ if (channel <= CH_MAX_2G_CHANNEL) ++ band = wiphy->bands[IEEE80211_BAND_2GHZ]; ++ else ++ band = wiphy->bands[IEEE80211_BAND_5GHZ]; ++ if (!band) { ++ AP6211_ERR("No valid band"); ++ if (body) ++ kfree(body); ++ return -EINVAL; ++ } ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) ++ freq = ieee80211_channel_to_frequency(channel); ++ (void)band->band; ++#else ++ freq = ieee80211_channel_to_frequency(channel, band->band); ++#endif ++ ++ err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid, ++ &mgmt_frame, &len, body); ++ if (err < 0) ++ goto exit; ++ isfree = true; ++ ++ if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) ++ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); ++#else ++ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ ++ } else if (event == WLC_E_DISASSOC_IND) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) ++ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); ++#else ++ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ ++ } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) ++ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); ++#else ++ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ ++ } ++ ++exit: ++ if (isfree) ++ kfree(mgmt_frame); ++ if (body) ++ kfree(body); ++ return err; ++#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !WL_CFG80211_STA_EVENT */ ++ sinfo.filled = 0; ++ if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) && ++ reason == DOT11_SC_SUCCESS) { ++ sinfo.filled = STATION_INFO_ASSOC_REQ_IES; ++ if (!data) { ++ AP6211_ERR("No IEs present in ASSOC/REASSOC_IND"); ++ return -EINVAL; ++ } ++ sinfo.assoc_req_ies = data; ++ sinfo.assoc_req_ies_len = len; ++ cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC); ++ } else if (event == WLC_E_DISASSOC_IND) { ++ cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); ++ } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { ++ cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); ++ } ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !WL_CFG80211_STA_EVENT */ ++ return err; ++} ++ ++static s32 ++wl_get_auth_assoc_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e) ++{ ++ u32 reason = ntoh32(e->reason); ++ u32 event = ntoh32(e->event_type); ++ struct wl_security *sec = wl_read_prof(wl, ndev, WL_PROF_SEC); ++ AP6211_DEBUG("event type : %d, reason : %d\n", event, reason); ++ if (sec) { ++ switch (event) { ++ case WLC_E_ASSOC: ++ case WLC_E_AUTH: ++ sec->auth_assoc_res_status = reason; ++ default: ++ break; ++ } ++ } else ++ AP6211_ERR("sec is NULL\n"); ++ return 0; ++} ++ ++static s32 ++wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ bool act; ++ s32 err = 0; ++ u32 event = ntoh32(e->event_type); ++ ++ if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { ++ wl_notify_connect_status_ap(wl, ndev, e, data); ++ } else { ++ AP6211_DEBUG("wl_notify_connect_status : event %d status : %d ndev %p\n", ++ ntoh32(e->event_type), ntoh32(e->status), ndev); ++ if (event == WLC_E_ASSOC || event == WLC_E_AUTH) { ++ wl_get_auth_assoc_status(wl, ndev, e); ++ return err; ++ } ++ if (wl_is_linkup(wl, e, ndev)) { ++ wl_link_up(wl); ++ act = true; ++ if (wl_is_ibssmode(wl, ndev)) { ++ AP6211_DEBUG("cfg80211_ibss_joined\n"); ++ cfg80211_ibss_joined(ndev, (s8 *)&e->addr, ++ GFP_KERNEL); ++ AP6211_DEBUG("joined in IBSS network\n"); ++ } else { ++ if (!wl_get_drv_status(wl, DISCONNECTING, ndev)) { ++ AP6211_DEBUG("wl_bss_connect_done succeeded with " MACDBG "\n", ++ MAC2STRDBG((u8*)(&e->addr))); ++ wl_bss_connect_done(wl, ndev, e, data, true); ++ AP6211_DEBUG("joined in BSS network \"%s\"\n", ++ ((struct wlc_ssid *) ++ wl_read_prof(wl, ndev, WL_PROF_SSID))->SSID); ++ } ++ } ++ wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT); ++ wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); ++ ++ } else if (wl_is_linkdown(wl, e)) { ++ if (wl->scan_request) { ++ if (wl->escan_on) { ++ wl_notify_escan_complete(wl, ndev, true, true); ++ } else { ++ del_timer_sync(&wl->scan_timeout); ++ wl_iscan_aborted(wl); ++ } ++ } ++ if (wl_get_drv_status(wl, CONNECTED, ndev)) { ++ scb_val_t scbval; ++ u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); ++ s32 reason = 0; ++ if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) ++ reason = ntoh32(e->reason); ++ /* WLAN_REASON_UNSPECIFIED is used for hang up event in Android */ ++ reason = (reason == WLAN_REASON_UNSPECIFIED)? 0 : reason; ++ ++ AP6211_DEBUG("link down if %s may call cfg80211_disconnected. " ++ "event : %d, reason=%d from " MACDBG "\n", ++ ndev->name, event, ntoh32(e->reason), ++ MAC2STRDBG((u8*)(&e->addr))); ++ if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) { ++ AP6211_ERR("BSSID of event is not the connected BSSID" ++ "(ignore it) cur: " MACDBG " event: " MACDBG"\n", ++ MAC2STRDBG(curbssid), MAC2STRDBG((u8*)(&e->addr))); ++ return 0; ++ } ++ wl_clr_drv_status(wl, CONNECTED, ndev); ++ if (! wl_get_drv_status(wl, DISCONNECTING, ndev)) { ++ /* To make sure disconnect, explictly send dissassoc ++ * for BSSID 00:00:00:00:00:00 issue ++ */ ++ scbval.val = WLAN_REASON_DEAUTH_LEAVING; ++ ++ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); ++ scbval.val = htod32(scbval.val); ++ err = wldev_ioctl(ndev, WLC_DISASSOC, &scbval, ++ sizeof(scb_val_t), true); ++ if (err < 0) { ++ AP6211_ERR("WLC_DISASSOC error %d\n", err); ++ err = 0; ++ } ++ cfg80211_disconnected(ndev, reason, NULL, 0, GFP_KERNEL); ++ wl_link_down(wl); ++ wl_init_prof(wl, ndev); ++ } ++ } ++ else if (wl_get_drv_status(wl, CONNECTING, ndev)) { ++ AP6211_DEBUG("link down, during connecting\n"); ++#ifdef ESCAN_RESULT_PATCH ++ if ((memcmp(connect_req_bssid, broad_bssid, ETHER_ADDR_LEN) == 0) || ++ (memcmp(&e->addr, broad_bssid, ETHER_ADDR_LEN) == 0) || ++ (memcmp(&e->addr, connect_req_bssid, ETHER_ADDR_LEN) == 0)) ++ /* In case this event comes while associating another AP */ ++#endif /* ESCAN_RESULT_PATCH */ ++ wl_bss_connect_done(wl, ndev, e, data, false); ++ } ++ wl_clr_drv_status(wl, DISCONNECTING, ndev); ++ ++ /* if link down, bsscfg is diabled */ ++ if (ndev != wl_to_prmry_ndev(wl)) ++ complete(&wl->iface_disable); ++ ++ } else if (wl_is_nonetwork(wl, e)) { ++ AP6211_DEBUG("connect failed event=%d e->status %d e->reason %d \n", ++ event, (int)ntoh32(e->status), (int)ntoh32(e->reason)); ++ /* Clean up any pending scan request */ ++ if (wl->scan_request) { ++ if (wl->escan_on) { ++ wl_notify_escan_complete(wl, ndev, true, true); ++ } else { ++ del_timer_sync(&wl->scan_timeout); ++ wl_iscan_aborted(wl); ++ } ++ } ++ if (wl_get_drv_status(wl, CONNECTING, ndev)) ++ wl_bss_connect_done(wl, ndev, e, data, false); ++ } else { ++ AP6211_DEBUG("%s nothing\n", __FUNCTION__); ++ } ++ } ++ return err; ++} ++ ++static s32 ++wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ bool act; ++ s32 err = 0; ++ u32 event = be32_to_cpu(e->event_type); ++ u32 status = be32_to_cpu(e->status); ++ AP6211_DEBUG("Enter \n"); ++ if (event == WLC_E_ROAM && status == WLC_E_STATUS_SUCCESS) { ++ if (wl_get_drv_status(wl, CONNECTED, ndev)) ++ wl_bss_roaming_done(wl, ndev, e, data); ++ else ++ wl_bss_connect_done(wl, ndev, e, data, true); ++ act = true; ++ wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT); ++ wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); ++ } ++ return err; ++} ++ ++static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev) ++{ ++ wl_assoc_info_t assoc_info; ++ struct wl_connect_info *conn_info = wl_to_conn(wl); ++ s32 err = 0; ++ ++ AP6211_DEBUG("Enter \n"); ++ err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, wl->extra_buf, ++ WL_ASSOC_INFO_MAX, NULL); ++ if (unlikely(err)) { ++ AP6211_ERR("could not get assoc info (%d)\n", err); ++ return err; ++ } ++ memcpy(&assoc_info, wl->extra_buf, sizeof(wl_assoc_info_t)); ++ assoc_info.req_len = htod32(assoc_info.req_len); ++ assoc_info.resp_len = htod32(assoc_info.resp_len); ++ assoc_info.flags = htod32(assoc_info.flags); ++ if (conn_info->req_ie_len) { ++ conn_info->req_ie_len = 0; ++ bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); ++ } ++ if (conn_info->resp_ie_len) { ++ conn_info->resp_ie_len = 0; ++ bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); ++ } ++ if (assoc_info.req_len) { ++ err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, wl->extra_buf, ++ WL_ASSOC_INFO_MAX, NULL); ++ if (unlikely(err)) { ++ AP6211_ERR("could not get assoc req (%d)\n", err); ++ return err; ++ } ++ conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); ++ if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { ++ conn_info->req_ie_len -= ETHER_ADDR_LEN; ++ } ++ if (conn_info->req_ie_len <= MAX_REQ_LINE) ++ memcpy(conn_info->req_ie, wl->extra_buf, conn_info->req_ie_len); ++ else { ++ AP6211_ERR("%s IE size %d above max %d size \n", ++ __FUNCTION__, conn_info->req_ie_len, MAX_REQ_LINE); ++ return err; ++ } ++ } else { ++ conn_info->req_ie_len = 0; ++ } ++ if (assoc_info.resp_len) { ++ err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, wl->extra_buf, ++ WL_ASSOC_INFO_MAX, NULL); ++ if (unlikely(err)) { ++ AP6211_ERR("could not get assoc resp (%d)\n", err); ++ return err; ++ } ++ conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); ++ if (conn_info->resp_ie_len <= MAX_REQ_LINE) ++ memcpy(conn_info->resp_ie, wl->extra_buf, conn_info->resp_ie_len); ++ else { ++ AP6211_ERR("%s IE size %d above max %d size \n", ++ __FUNCTION__, conn_info->resp_ie_len, MAX_REQ_LINE); ++ return err; ++ } ++ } else { ++ conn_info->resp_ie_len = 0; ++ } ++ AP6211_DEBUG("req len (%d) resp len (%d)\n", conn_info->req_ie_len, ++ conn_info->resp_ie_len); ++ ++ return err; ++} ++ ++static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, ++ size_t *join_params_size) ++{ ++ chanspec_t chanspec = 0; ++ if (ch != 0) { ++ join_params->params.chanspec_num = 1; ++ join_params->params.chanspec_list[0] = ch; ++ ++ if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL) ++ chanspec |= WL_CHANSPEC_BAND_2G; ++ else ++ chanspec |= WL_CHANSPEC_BAND_5G; ++ ++ chanspec |= WL_CHANSPEC_BW_20; ++ chanspec |= WL_CHANSPEC_CTL_SB_NONE; ++ ++ *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE + ++ join_params->params.chanspec_num * sizeof(chanspec_t); ++ ++ join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; ++ join_params->params.chanspec_list[0] |= chanspec; ++ join_params->params.chanspec_list[0] = ++ wl_chspec_host_to_driver(join_params->params.chanspec_list[0]); ++ ++ join_params->params.chanspec_num = ++ htod32(join_params->params.chanspec_num); ++ AP6211_DEBUG("join_params->params.chanspec_list[0]= %X, %d channels\n", ++ join_params->params.chanspec_list[0], ++ join_params->params.chanspec_num); ++ } ++} ++ ++static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is_roam_done) ++{ ++ struct cfg80211_bss *bss; ++ struct wl_bss_info *bi; ++ struct wlc_ssid *ssid; ++ struct bcm_tlv *tim; ++ s32 beacon_interval; ++ s32 dtim_period; ++ size_t ie_len; ++ u8 *ie; ++ u8 *ssidie; ++ u8 *curbssid; ++ s32 err = 0; ++ struct wiphy *wiphy; ++ ++ wiphy = wl_to_wiphy(wl); ++ ++ if (wl_is_ibssmode(wl, ndev)) ++ return err; ++ ++ ssid = (struct wlc_ssid *)wl_read_prof(wl, ndev, WL_PROF_SSID); ++ curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); ++ bss = cfg80211_get_bss(wiphy, NULL, curbssid, ++ ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS, ++ WLAN_CAPABILITY_ESS); ++ ++ mutex_lock(&wl->usr_sync); ++ if (!bss) { ++ AP6211_DEBUG("Could not find the AP\n"); ++ *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); ++ err = wldev_ioctl(ndev, WLC_GET_BSS_INFO, ++ wl->extra_buf, WL_EXTRA_BUF_MAX, false); ++ if (unlikely(err)) { ++ AP6211_ERR("Could not get bss info %d\n", err); ++ goto update_bss_info_out; ++ } ++ bi = (struct wl_bss_info *)(wl->extra_buf + 4); ++ if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) { ++ err = -EIO; ++ goto update_bss_info_out; ++ } ++ ++ ie = ((u8 *)bi) + bi->ie_offset; ++ ie_len = bi->ie_length; ++ ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie, ie_len); ++ if (ssidie && ssidie[1] == bi->SSID_len && !ssidie[2] && bi->SSID[0]) ++ memcpy(ssidie + 2, bi->SSID, bi->SSID_len); ++ ++ err = wl_inform_single_bss(wl, bi, is_roam_done); ++ if (unlikely(err)) ++ goto update_bss_info_out; ++ ++ ie = ((u8 *)bi) + bi->ie_offset; ++ ie_len = bi->ie_length; ++ beacon_interval = cpu_to_le16(bi->beacon_period); ++ } else { ++ AP6211_DEBUG("Found the AP in the list - BSSID %pM\n", bss->bssid); ++ ie = bss->information_elements; ++ ie_len = bss->len_information_elements; ++ beacon_interval = bss->beacon_interval; ++ cfg80211_put_bss(bss); ++ } ++ ++ tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM); ++ if (tim) { ++ dtim_period = tim->data[1]; ++ } else { ++ /* ++ * active scan was done so we could not get dtim ++ * information out of probe response. ++ * so we speficially query dtim information. ++ */ ++ err = wldev_ioctl(ndev, WLC_GET_DTIMPRD, ++ &dtim_period, sizeof(dtim_period), false); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_GET_DTIMPRD error (%d)\n", err); ++ goto update_bss_info_out; ++ } ++ } ++ ++ wl_update_prof(wl, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT); ++ wl_update_prof(wl, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD); ++ ++update_bss_info_out: ++ mutex_unlock(&wl->usr_sync); ++ return err; ++} ++ ++static s32 ++wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ struct wl_connect_info *conn_info = wl_to_conn(wl); ++ s32 err = 0; ++ u8 *curbssid; ++ ++ wl_get_assoc_ies(wl, ndev); ++ wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); ++ curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); ++ wl_update_bss_info(wl, ndev, 1); ++ wl_update_pmklist(ndev, wl->pmk_list, err); ++ AP6211_DEBUG("wl_bss_roaming_done succeeded to " MACDBG "\n", ++ MAC2STRDBG((u8*)(&e->addr))); ++ ++ cfg80211_roamed(ndev, ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) ++ NULL, /* struct cfg80211_bss *bss */ ++#elif LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) ++ NULL, ++#endif ++ curbssid, ++ conn_info->req_ie, conn_info->req_ie_len, ++ conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); ++ AP6211_DEBUG("Report roaming result\n"); ++ ++ wl_set_drv_status(wl, CONNECTED, ndev); ++ ++ return err; ++} ++ ++static s32 ++wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data, bool completed) ++{ ++ struct wl_connect_info *conn_info = wl_to_conn(wl); ++ struct wl_security *sec = wl_read_prof(wl, ndev, WL_PROF_SEC); ++ s32 err = 0; ++ u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); ++ if (!sec) { ++ AP6211_ERR("sec is NULL\n"); ++ return -ENODEV; ++ } ++ AP6211_DEBUG(" enter\n"); ++#ifdef ESCAN_RESULT_PATCH ++ if (wl_get_drv_status(wl, CONNECTED, ndev)) { ++ if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) { ++ AP6211_DEBUG(" Connected event of connected device e=%d s=%d, ignore it\n", ++ ntoh32(e->event_type), ntoh32(e->status)); ++ return err; ++ } ++ } ++ if (memcmp(curbssid, broad_bssid, ETHER_ADDR_LEN) == 0 && ++ memcmp(broad_bssid, connect_req_bssid, ETHER_ADDR_LEN) != 0) { ++ AP6211_DEBUG("copy bssid\n"); ++ memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN); ++ } ++ ++#else ++ if (wl->scan_request) { ++ wl_notify_escan_complete(wl, ndev, true, true); ++ } ++#endif /* ESCAN_RESULT_PATCH */ ++ if (wl_get_drv_status(wl, CONNECTING, ndev)) { ++ wl_clr_drv_status(wl, CONNECTING, ndev); ++ if (completed) { ++ wl_get_assoc_ies(wl, ndev); ++ wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); ++ curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); ++ wl_update_bss_info(wl, ndev, 0); ++ wl_update_pmklist(ndev, wl->pmk_list, err); ++ wl_set_drv_status(wl, CONNECTED, ndev); ++ } ++ cfg80211_connect_result(ndev, ++ curbssid, ++ conn_info->req_ie, ++ conn_info->req_ie_len, ++ conn_info->resp_ie, ++ conn_info->resp_ie_len, ++ completed ? WLAN_STATUS_SUCCESS : ++ (sec->auth_assoc_res_status) ? ++ sec->auth_assoc_res_status : ++ WLAN_STATUS_UNSPECIFIED_FAILURE, ++ GFP_KERNEL); ++ if (completed) ++ AP6211_DEBUG("Report connect result - connection succeeded\n"); ++ else ++ AP6211_ERR("Report connect result - connection failed\n"); ++ } ++ return err; ++} ++ ++static s32 ++wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ u16 flags = ntoh16(e->flags); ++ enum nl80211_key_type key_type; ++ ++ mutex_lock(&wl->usr_sync); ++ if (flags & WLC_EVENT_MSG_GROUP) ++ key_type = NL80211_KEYTYPE_GROUP; ++ else ++ key_type = NL80211_KEYTYPE_PAIRWISE; ++ ++ cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1, ++ NULL, GFP_KERNEL); ++ mutex_unlock(&wl->usr_sync); ++ ++ return 0; ++} ++ ++#ifdef PNO_SUPPORT ++static s32 ++wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ AP6211_ERR(">>> PNO Event\n"); ++ ++#ifndef WL_SCHED_SCAN ++ mutex_lock(&wl->usr_sync); ++ /* TODO: Use cfg80211_sched_scan_results(wiphy); */ ++ cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); ++ mutex_unlock(&wl->usr_sync); ++#else ++ /* If cfg80211 scheduled scan is supported, report the pno results via sched ++ * scan results ++ */ ++ wl_notify_sched_scan_results(wl, ndev, e, data); ++#endif /* WL_SCHED_SCAN */ ++ return 0; ++} ++#endif /* PNO_SUPPORT */ ++ ++static s32 ++wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ struct channel_info channel_inform; ++ struct wl_scan_results *bss_list; ++ u32 len = WL_SCAN_BUF_MAX; ++ s32 err = 0; ++ unsigned long flags; ++ ++ AP6211_DEBUG("Enter \n"); ++ if (!wl_get_drv_status(wl, SCANNING, ndev)) { ++ AP6211_ERR("scan is not ready \n"); ++ return err; ++ } ++ if (wl->iscan_on && wl->iscan_kickstart) ++ return wl_wakeup_iscan(wl_to_iscan(wl)); ++ ++ mutex_lock(&wl->usr_sync); ++ wl_clr_drv_status(wl, SCANNING, ndev); ++ err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform, ++ sizeof(channel_inform), false); ++ if (unlikely(err)) { ++ AP6211_ERR("scan busy (%d)\n", err); ++ goto scan_done_out; ++ } ++ channel_inform.scan_channel = dtoh32(channel_inform.scan_channel); ++ if (unlikely(channel_inform.scan_channel)) { ++ ++ AP6211_DEBUG("channel_inform.scan_channel (%d)\n", ++ channel_inform.scan_channel); ++ } ++ wl->bss_list = wl->scan_results; ++ bss_list = wl->bss_list; ++ memset(bss_list, 0, len); ++ bss_list->buflen = htod32(len); ++ err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, false); ++ if (unlikely(err) && unlikely(!wl->scan_suppressed)) { ++ AP6211_ERR("%s Scan_results error (%d)\n", ndev->name, err); ++ err = -EINVAL; ++ goto scan_done_out; ++ } ++ bss_list->buflen = dtoh32(bss_list->buflen); ++ bss_list->version = dtoh32(bss_list->version); ++ bss_list->count = dtoh32(bss_list->count); ++ ++ err = wl_inform_bss(wl); ++ ++scan_done_out: ++ del_timer_sync(&wl->scan_timeout); ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ if (wl->scan_request) { ++ cfg80211_scan_done(wl->scan_request, false); ++ wl->scan_request = NULL; ++ } ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ AP6211_DEBUG("cfg80211_scan_done\n"); ++ mutex_unlock(&wl->usr_sync); ++ return err; ++} ++static s32 ++wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, ++ const struct ether_addr *sa, const struct ether_addr *bssid, ++ u8 **pheader, u32 *body_len, u8 *pbody) ++{ ++ struct dot11_management_header *hdr; ++ u32 totlen = 0; ++ s32 err = 0; ++ u8 *offset; ++ u32 prebody_len = *body_len; ++ switch (fc) { ++ case FC_ASSOC_REQ: ++ /* capability , listen interval */ ++ totlen = DOT11_ASSOC_REQ_FIXED_LEN; ++ *body_len += DOT11_ASSOC_REQ_FIXED_LEN; ++ break; ++ ++ case FC_REASSOC_REQ: ++ /* capability, listen inteval, ap address */ ++ totlen = DOT11_REASSOC_REQ_FIXED_LEN; ++ *body_len += DOT11_REASSOC_REQ_FIXED_LEN; ++ break; ++ } ++ totlen += DOT11_MGMT_HDR_LEN + prebody_len; ++ *pheader = kzalloc(totlen, GFP_KERNEL); ++ if (*pheader == NULL) { ++ AP6211_ERR("memory alloc failed \n"); ++ return -ENOMEM; ++ } ++ hdr = (struct dot11_management_header *) (*pheader); ++ hdr->fc = htol16(fc); ++ hdr->durid = 0; ++ hdr->seq = 0; ++ offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len); ++ bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN); ++ bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN); ++ bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN); ++ if ((pbody != NULL) && prebody_len) ++ bcopy((const char*)pbody, offset, prebody_len); ++ *body_len = totlen; ++ return err; ++} ++ ++ ++void ++wl_stop_wait_next_action_frame(struct wl_priv *wl, struct net_device *ndev) ++{ ++ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM) && ++ (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || ++ wl_get_p2p_status(wl, ACTION_TX_NOACK))) { ++ AP6211_DEBUG("*** Wake UP ** abort actframe iovar\n"); ++ /* if channel is not zero, "actfame" uses off channel scan. ++ * So abort scan for off channel completion. ++ */ ++ if (wl->af_sent_channel) ++ /* wl_cfg80211_scan_abort(wl, ndev); */ ++ wl_notify_escan_complete(wl, ++ (ndev == wl->p2p_net) ? wl_to_prmry_ndev(wl) : ndev, true, true); ++ } ++#ifdef WL_CFG80211_SYNC_GON ++ else if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) { ++ AP6211_DEBUG("*** Wake UP ** abort listen for next af frame\n"); ++ /* So abort scan to cancel listen */ ++ wl_notify_escan_complete(wl, ++ (ndev == wl->p2p_net) ? wl_to_prmry_ndev(wl) : ndev, true, true); ++ } ++#endif /* WL_CFG80211_SYNC_GON */ ++} ++ ++static s32 ++wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ struct ieee80211_supported_band *band; ++ struct wiphy *wiphy = wl_to_wiphy(wl); ++ struct ether_addr da; ++ struct ether_addr bssid; ++ bool isfree = false; ++ s32 err = 0; ++ s32 freq; ++ struct net_device *dev = NULL; ++ wifi_p2p_pub_act_frame_t *act_frm = NULL; ++ wifi_p2p_action_frame_t *p2p_act_frm = NULL; ++ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; ++ wl_event_rx_frame_data_t *rxframe = ++ (wl_event_rx_frame_data_t*)data; ++ u32 event = ntoh32(e->event_type); ++ u8 *mgmt_frame; ++ u8 bsscfgidx = e->bsscfgidx; ++ u32 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t); ++ u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK)); ++ ++ memset(&bssid, 0, ETHER_ADDR_LEN); ++ ++ if (wl->p2p_net == ndev) { ++ dev = wl_to_prmry_ndev(wl); ++ } else { ++ dev = ndev; ++ } ++ ++ if (channel <= CH_MAX_2G_CHANNEL) ++ band = wiphy->bands[IEEE80211_BAND_2GHZ]; ++ else ++ band = wiphy->bands[IEEE80211_BAND_5GHZ]; ++ if (!band) { ++ AP6211_ERR("No valid band"); ++ return -EINVAL; ++ } ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) ++ freq = ieee80211_channel_to_frequency(channel); ++ (void)band->band; ++#else ++ freq = ieee80211_channel_to_frequency(channel, band->band); ++#endif ++ if (event == WLC_E_ACTION_FRAME_RX) { ++ wldev_iovar_getbuf_bsscfg(dev, "cur_etheraddr", ++ NULL, 0, wl->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &wl->ioctl_buf_sync); ++ ++ err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); ++ if (err < 0) ++ AP6211_ERR("WLC_GET_BSSID error %d\n", err); ++ memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN); ++ err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid, ++ &mgmt_frame, &mgmt_frame_len, ++ (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1)); ++ if (err < 0) { ++ AP6211_ERR("%s: Error in receiving action frame len %d channel %d freq %d\n", ++ __func__, mgmt_frame_len, channel, freq); ++ goto exit; ++ } ++ isfree = true; ++ if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], ++ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { ++ act_frm = (wifi_p2p_pub_act_frame_t *) ++ (&mgmt_frame[DOT11_MGMT_HDR_LEN]); ++ } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], ++ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { ++ p2p_act_frm = (wifi_p2p_action_frame_t *) ++ (&mgmt_frame[DOT11_MGMT_HDR_LEN]); ++ (void) p2p_act_frm; ++ } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], ++ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { ++ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) ++ (&mgmt_frame[DOT11_MGMT_HDR_LEN]); ++ if (sd_act_frm && wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM)) { ++ if (wl->next_af_subtype == sd_act_frm->action) { ++ AP6211_DEBUG("We got a right next frame of SD!(%d)\n", ++ sd_act_frm->action); ++ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, ++ (ndev == wl->p2p_net) ? ++ wl_to_prmry_ndev(wl) : ndev); ++ ++ /* Stop waiting for next AF. */ ++ wl_stop_wait_next_action_frame(wl, ndev); ++ } ++ } ++ (void) sd_act_frm; ++ } else { ++ /* ++ * if we got normal action frame and ndev is p2p0, ++ * we have to change ndev from p2p0 to wlan0 ++ */ ++ if (wl->p2p_net == ndev) ++ ndev = wl_to_prmry_ndev(wl); ++ } ++ ++ if (act_frm) { ++ ++ if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM)) { ++ if (wl->next_af_subtype == act_frm->subtype) { ++ AP6211_DEBUG("We got a right next frame!(%d)\n", ++ act_frm->subtype); ++ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, ++ (ndev == wl->p2p_net) ? ++ wl_to_prmry_ndev(wl) : ndev); ++ ++ /* Stop waiting for next AF. */ ++ wl_stop_wait_next_action_frame(wl, ndev); ++ } ++ } ++ } ++ ++ wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN], ++ mgmt_frame_len - DOT11_MGMT_HDR_LEN); ++ /* ++ * After complete GO Negotiation, roll back to mpc mode ++ */ ++ if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) || ++ (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { ++ wldev_iovar_setint(dev, "mpc", 1); ++ } ++ if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) { ++ AP6211_DEBUG("P2P: GO_NEG_PHASE status cleared \n"); ++ wl_clr_p2p_status(wl, GO_NEG_PHASE); ++ } ++ } else { ++ mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); ++ ++ /* wpa supplicant use probe request event for restarting another GON Req. ++ * but it makes GON Req repetition. ++ * so if src addr of prb req is same as my target device, ++ * do not send probe request event during sending action frame. ++ */ ++ if (event == WLC_E_P2P_PROBREQ_MSG) { ++ AP6211_DEBUG(" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ? ++ "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG"); ++ ++ ++ /* Filter any P2P probe reqs arriving during the ++ * GO-NEG Phase ++ */ ++ if (wl->p2p && ++ wl_get_p2p_status(wl, GO_NEG_PHASE)) { ++ AP6211_DEBUG("Filtering P2P probe_req while " ++ "being in GO-Neg state\n"); ++ return 0; ++ } ++ } ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) ++ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); ++#else ++ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ ++ ++ AP6211_DEBUG("%s: mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n", __func__, ++ mgmt_frame_len, ntoh32(e->datalen), channel, freq); ++exit: ++ if (isfree) ++ kfree(mgmt_frame); ++ return 0; ++} ++ ++#ifdef WL_SCHED_SCAN ++/* If target scan is not reliable, set the below define to "1" to do a ++ * full escan ++ */ ++#define FULL_ESCAN_ON_PFN_NET_FOUND 0 ++static s32 ++wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ wl_pfn_net_info_t *netinfo, *pnetinfo; ++ struct cfg80211_scan_request request; ++ struct wiphy *wiphy = wl_to_wiphy(wl); ++ int err = 0; ++ struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT]; ++ struct ieee80211_channel *channel = NULL; ++ int channel_req = 0; ++ int band = 0; ++ struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data; ++ ++ AP6211_DEBUG("Enter\n"); ++ ++ if (e->event_type == WLC_E_PFN_NET_LOST) { ++ AP6211_DEBUG("PFN NET LOST event. Do Nothing \n"); ++ return 0; ++ } ++ AP6211_DEBUG(">>> PFN NET FOUND event. count:%d \n", pfn_result->count); ++ if (pfn_result->count > 0) { ++ int i; ++ ++ memset(&request, 0x00, sizeof(struct cfg80211_scan_request)); ++ memset(&ssid, 0x00, sizeof(ssid)); ++ request.wiphy = wiphy; ++ ++ pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t) ++ - sizeof(wl_pfn_net_info_t)); ++ channel = (struct ieee80211_channel *)kzalloc( ++ (sizeof(struct ieee80211_channel) * MAX_PFN_LIST_COUNT), ++ GFP_KERNEL); ++ if (!channel) { ++ AP6211_ERR("No memory"); ++ err = -ENOMEM; ++ goto out_err; ++ } ++ ++ for (i = 0; i < pfn_result->count; i++) { ++ netinfo = &pnetinfo[i]; ++ if (!netinfo) { ++ AP6211_ERR("Invalid netinfo ptr. index:%d", i); ++ err = -EINVAL; ++ goto out_err; ++ } ++ AP6211_DEBUG(">>> SSID:%s Channel:%d \n", ++ netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel); ++ /* PFN result doesn't have all the info which are required by the supplicant ++ * (For e.g IEs) Do a target Escan so that sched scan results are reported ++ * via wl_inform_single_bss in the required format. Escan does require the ++ * scan request in the form of cfg80211_scan_request. For timebeing, create ++ * cfg80211_scan_request one out of the received PNO event. ++ */ ++ memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID, ++ netinfo->pfnsubnet.SSID_len); ++ ssid[i].ssid_len = netinfo->pfnsubnet.SSID_len; ++ request.n_ssids++; ++ ++ channel_req = netinfo->pfnsubnet.channel; ++ band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ ++ : NL80211_BAND_5GHZ; ++ channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band); ++ channel[i].band = band; ++ channel[i].flags |= IEEE80211_CHAN_NO_HT40; ++ request.channels[i] = &channel[i]; ++ request.n_channels++; ++ } ++ ++ /* assign parsed ssid array */ ++ if (request.n_ssids) ++ request.ssids = &ssid[0]; ++ ++ if (wl_get_drv_status_all(wl, SCANNING)) { ++ /* Abort any on-going scan */ ++ wl_notify_escan_complete(wl, ndev, true, true); ++ } ++ ++ if (wl_get_p2p_status(wl, DISCOVERY_ON)) { ++ AP6211_DEBUG(">>> P2P discovery was ON. Disabling it\n"); ++ err = wl_cfgp2p_discover_enable_search(wl, false); ++ if (unlikely(err)) { ++ wl_clr_drv_status(wl, SCANNING, ndev); ++ goto out_err; ++ } ++ } ++ ++ wl_set_drv_status(wl, SCANNING, ndev); ++#if FULL_ESCAN_ON_PFN_NET_FOUND ++ AP6211_DEBUG(">>> Doing Full ESCAN on PNO event\n"); ++ err = wl_do_escan(wl, wiphy, ndev, NULL); ++#else ++ AP6211_DEBUG(">>> Doing targeted ESCAN on PNO event\n"); ++ err = wl_do_escan(wl, wiphy, ndev, &request); ++#endif ++ if (err) { ++ wl_clr_drv_status(wl, SCANNING, ndev); ++ goto out_err; ++ } ++ wl->sched_scan_running = TRUE; ++ } ++ else { ++ AP6211_ERR("FALSE PNO Event. (pfn_count == 0) \n"); ++ } ++out_err: ++ if (channel) ++ kfree(channel); ++ return err; ++} ++#endif /* WL_SCHED_SCAN */ ++ ++static void wl_init_conf(struct wl_conf *conf) ++{ ++ AP6211_DEBUG("Enter \n"); ++ conf->frag_threshold = (u32)-1; ++ conf->rts_threshold = (u32)-1; ++ conf->retry_short = (u32)-1; ++ conf->retry_long = (u32)-1; ++ conf->tx_power = -1; ++} ++ ++static void wl_init_prof(struct wl_priv *wl, struct net_device *ndev) ++{ ++ unsigned long flags; ++ struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); ++ ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ memset(profile, 0, sizeof(struct wl_profile)); ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++} ++ ++static void wl_init_event_handler(struct wl_priv *wl) ++{ ++ memset(wl->evt_handler, 0, sizeof(wl->evt_handler)); ++ ++ wl->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status; ++ wl->evt_handler[WLC_E_AUTH] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_LINK] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status; ++ wl->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status; ++ wl->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status; ++ wl->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame; ++ wl->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; ++ wl->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; ++ wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete; ++ wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete; ++ wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete; ++#ifdef PNO_SUPPORT ++ wl->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status; ++#endif /* PNO_SUPPORT */ ++} ++ ++static s32 wl_init_priv_mem(struct wl_priv *wl) ++{ ++ AP6211_DEBUG("Enter \n"); ++ wl->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); ++ if (unlikely(!wl->scan_results)) { ++ AP6211_ERR("Scan results alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->conf = (void *)kzalloc(sizeof(*wl->conf), GFP_KERNEL); ++ if (unlikely(!wl->conf)) { ++ AP6211_ERR("wl_conf alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->scan_req_int = ++ (void *)kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL); ++ if (unlikely(!wl->scan_req_int)) { ++ AP6211_ERR("Scan req alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); ++ if (unlikely(!wl->ioctl_buf)) { ++ AP6211_ERR("Ioctl buf alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); ++ if (unlikely(!wl->escan_ioctl_buf)) { ++ AP6211_ERR("Ioctl buf alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); ++ if (unlikely(!wl->extra_buf)) { ++ AP6211_ERR("Extra buf alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->iscan = (void *)kzalloc(sizeof(*wl->iscan), GFP_KERNEL); ++ if (unlikely(!wl->iscan)) { ++ AP6211_ERR("Iscan buf alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->pmk_list = (void *)kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL); ++ if (unlikely(!wl->pmk_list)) { ++ AP6211_ERR("pmk list alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->sta_info = (void *)kzalloc(sizeof(*wl->sta_info), GFP_KERNEL); ++ if (unlikely(!wl->sta_info)) { ++ AP6211_ERR("sta info alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ ++#if defined(STATIC_WL_PRIV_STRUCT) ++ wl->conn_info = (void *)kzalloc(sizeof(*wl->conn_info), GFP_KERNEL); ++ if (unlikely(!wl->conn_info)) { ++ AP6211_ERR("wl->conn_info alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->ie = (void *)kzalloc(sizeof(*wl->ie), GFP_KERNEL); ++ if (unlikely(!wl->ie)) { ++ AP6211_ERR("wl->ie alloc failed\n"); ++ goto init_priv_mem_out; ++ } ++ wl->escan_info.escan_buf = dhd_os_prealloc(NULL, DHD_PREALLOC_WIPHY_ESCAN0, 0); ++ bzero(wl->escan_info.escan_buf, ESCAN_BUF_SIZE); ++#endif /* STATIC_WL_PRIV_STRUCT */ ++ wl->afx_hdl = (void *)kzalloc(sizeof(*wl->afx_hdl), GFP_KERNEL); ++ if (unlikely(!wl->afx_hdl)) { ++ AP6211_ERR("afx hdl alloc failed\n"); ++ goto init_priv_mem_out; ++ } else { ++ init_completion(&wl->act_frm_scan); ++ init_completion(&wl->wait_next_af); ++ ++ INIT_WORK(&wl->afx_hdl->work, wl_cfg80211_afx_handler); ++ } ++ return 0; ++ ++init_priv_mem_out: ++ wl_deinit_priv_mem(wl); ++ ++ return -ENOMEM; ++} ++ ++static void wl_deinit_priv_mem(struct wl_priv *wl) ++{ ++ kfree(wl->scan_results); ++ wl->scan_results = NULL; ++ kfree(wl->conf); ++ wl->conf = NULL; ++ kfree(wl->scan_req_int); ++ wl->scan_req_int = NULL; ++ kfree(wl->ioctl_buf); ++ wl->ioctl_buf = NULL; ++ kfree(wl->escan_ioctl_buf); ++ wl->escan_ioctl_buf = NULL; ++ kfree(wl->extra_buf); ++ wl->extra_buf = NULL; ++ kfree(wl->iscan); ++ wl->iscan = NULL; ++ kfree(wl->pmk_list); ++ wl->pmk_list = NULL; ++ kfree(wl->sta_info); ++ wl->sta_info = NULL; ++#if defined(STATIC_WL_PRIV_STRUCT) ++ kfree(wl->conn_info); ++ wl->conn_info = NULL; ++ kfree(wl->ie); ++ wl->ie = NULL; ++ wl->escan_info.escan_buf = NULL; ++#endif /* STATIC_WL_PRIV_STRUCT */ ++ if (wl->afx_hdl) { ++ cancel_work_sync(&wl->afx_hdl->work); ++ kfree(wl->afx_hdl); ++ wl->afx_hdl = NULL; ++ } ++ ++ if (wl->ap_info) { ++ kfree(wl->ap_info->wpa_ie); ++ kfree(wl->ap_info->rsn_ie); ++ kfree(wl->ap_info->wps_ie); ++ kfree(wl->ap_info); ++ wl->ap_info = NULL; ++ } ++} ++ ++static s32 wl_create_event_handler(struct wl_priv *wl) ++{ ++ int ret = 0; ++ AP6211_DEBUG("Enter \n"); ++ ++ /* Do not use DHD in cfg driver */ ++ wl->event_tsk.thr_pid = -1; ++ ++#ifdef USE_KTHREAD_API ++ PROC_START2(wl_event_handler, wl, &wl->event_tsk, 0, "wl_event_handler"); ++#else ++ PROC_START(wl_event_handler, wl, &wl->event_tsk, 0); ++#endif ++ if (wl->event_tsk.thr_pid < 0) ++ ret = -ENOMEM; ++ return ret; ++} ++ ++static void wl_destroy_event_handler(struct wl_priv *wl) ++{ ++ if (wl->event_tsk.thr_pid >= 0) ++ PROC_STOP(&wl->event_tsk); ++} ++ ++static void wl_term_iscan(struct wl_priv *wl) ++{ ++ struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); ++ AP6211_DEBUG("In\n"); ++ if (wl->iscan_on && iscan->tsk) { ++ iscan->state = WL_ISCAN_STATE_IDLE; ++ AP6211_DEBUG("SIGTERM\n"); ++ send_sig(SIGTERM, iscan->tsk, 1); ++ AP6211_DEBUG("kthread_stop\n"); ++ kthread_stop(iscan->tsk); ++ iscan->tsk = NULL; ++ } ++} ++ ++static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted) ++{ ++ struct wl_priv *wl = iscan_to_wl(iscan); ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ unsigned long flags; ++ ++ AP6211_DEBUG("Enter \n"); ++ if (!wl_get_drv_status(wl, SCANNING, ndev)) { ++ wl_clr_drv_status(wl, SCANNING, ndev); ++ AP6211_ERR("Scan complete while device not scanning\n"); ++ return; ++ } ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ wl_clr_drv_status(wl, SCANNING, ndev); ++ if (likely(wl->scan_request)) { ++ cfg80211_scan_done(wl->scan_request, aborted); ++ wl->scan_request = NULL; ++ } ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ wl->iscan_kickstart = false; ++} ++ ++static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan) ++{ ++ if (likely(iscan->state != WL_ISCAN_STATE_IDLE)) { ++ AP6211_DEBUG("wake up iscan\n"); ++ up(&iscan->sync); ++ return 0; ++ } ++ ++ return -EIO; ++} ++ ++static s32 ++wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status, ++ struct wl_scan_results **bss_list) ++{ ++ struct wl_iscan_results list; ++ struct wl_scan_results *results; ++ struct wl_iscan_results *list_buf; ++ s32 err = 0; ++ ++ AP6211_DEBUG("Enter \n"); ++ memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX); ++ list_buf = (struct wl_iscan_results *)iscan->scan_buf; ++ results = &list_buf->results; ++ results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE; ++ results->version = 0; ++ results->count = 0; ++ ++ memset(&list, 0, sizeof(list)); ++ list.results.buflen = htod32(WL_ISCAN_BUF_MAX); ++ err = wldev_iovar_getbuf(iscan->dev, "iscanresults", &list, ++ WL_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf, ++ WL_ISCAN_BUF_MAX, NULL); ++ if (unlikely(err)) { ++ AP6211_ERR("error (%d)\n", err); ++ return err; ++ } ++ results->buflen = dtoh32(results->buflen); ++ results->version = dtoh32(results->version); ++ results->count = dtoh32(results->count); ++ AP6211_DEBUG("results->count = %d\n", results->count); ++ AP6211_DEBUG("results->buflen = %d\n", results->buflen); ++ *status = dtoh32(list_buf->status); ++ *bss_list = results; ++ ++ return err; ++} ++ ++static s32 wl_iscan_done(struct wl_priv *wl) ++{ ++ struct wl_iscan_ctrl *iscan = wl->iscan; ++ s32 err = 0; ++ ++ iscan->state = WL_ISCAN_STATE_IDLE; ++ mutex_lock(&wl->usr_sync); ++ wl_inform_bss(wl); ++ wl_notify_iscan_complete(iscan, false); ++ mutex_unlock(&wl->usr_sync); ++ ++ return err; ++} ++ ++static s32 wl_iscan_pending(struct wl_priv *wl) ++{ ++ struct wl_iscan_ctrl *iscan = wl->iscan; ++ s32 err = 0; ++ ++ /* Reschedule the timer */ ++ mod_timer(&iscan->timer, jiffies + msecs_to_jiffies(iscan->timer_ms)); ++ iscan->timer_on = 1; ++ ++ return err; ++} ++ ++static s32 wl_iscan_inprogress(struct wl_priv *wl) ++{ ++ struct wl_iscan_ctrl *iscan = wl->iscan; ++ s32 err = 0; ++ ++ mutex_lock(&wl->usr_sync); ++ wl_inform_bss(wl); ++ wl_run_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE); ++ mutex_unlock(&wl->usr_sync); ++ /* Reschedule the timer */ ++ mod_timer(&iscan->timer, jiffies + msecs_to_jiffies(iscan->timer_ms)); ++ iscan->timer_on = 1; ++ ++ return err; ++} ++ ++static s32 wl_iscan_aborted(struct wl_priv *wl) ++{ ++ struct wl_iscan_ctrl *iscan = wl->iscan; ++ s32 err = 0; ++ ++ iscan->state = WL_ISCAN_STATE_IDLE; ++ mutex_lock(&wl->usr_sync); ++ wl_notify_iscan_complete(iscan, true); ++ mutex_unlock(&wl->usr_sync); ++ ++ return err; ++} ++ ++static s32 wl_iscan_thread(void *data) ++{ ++ struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data; ++ struct wl_priv *wl = iscan_to_wl(iscan); ++ u32 status; ++ int err = 0; ++ ++ allow_signal(SIGTERM); ++ status = WL_SCAN_RESULTS_PARTIAL; ++ while (likely(!down_interruptible(&iscan->sync))) { ++ if (kthread_should_stop()) ++ break; ++ if (iscan->timer_on) { ++ del_timer_sync(&iscan->timer); ++ iscan->timer_on = 0; ++ } ++ mutex_lock(&wl->usr_sync); ++ err = wl_get_iscan_results(iscan, &status, &wl->bss_list); ++ if (unlikely(err)) { ++ status = WL_SCAN_RESULTS_ABORTED; ++ AP6211_ERR("Abort iscan\n"); ++ } ++ mutex_unlock(&wl->usr_sync); ++ iscan->iscan_handler[status] (wl); ++ } ++ if (iscan->timer_on) { ++ del_timer_sync(&iscan->timer); ++ iscan->timer_on = 0; ++ } ++ AP6211_DEBUG("%s was terminated\n", __func__); ++ ++ return 0; ++} ++ ++static void wl_scan_timeout(unsigned long data) ++{ ++ wl_event_msg_t msg; ++ struct wl_priv *wl = (struct wl_priv *)data; ++ ++ if (!(wl->scan_request)) { ++ AP6211_ERR("timer expired but no scan request\n"); ++ return; ++ } ++ bzero(&msg, sizeof(wl_event_msg_t)); ++ AP6211_ERR("timer expired\n"); ++ if (wl->escan_on) { ++ msg.event_type = hton32(WLC_E_ESCAN_RESULT); ++ msg.status = hton32(WLC_E_STATUS_TIMEOUT); ++ msg.reason = 0xFFFFFFFF; ++ wl_cfg80211_event(wl_to_prmry_ndev(wl), &msg, NULL); ++ } else { ++ AP6211_ERR("SCAN Timeout(ISCAN)\n"); ++ wl_notify_iscan_complete(wl_to_iscan(wl), true); ++ } ++} ++static void wl_iscan_timer(unsigned long data) ++{ ++ struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data; ++ ++ if (iscan) { ++ iscan->timer_on = 0; ++ AP6211_DEBUG("timer expired\n"); ++ wl_wakeup_iscan(iscan); ++ } ++} ++ ++static s32 wl_invoke_iscan(struct wl_priv *wl) ++{ ++ struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); ++ int err = 0; ++ ++ if (wl->iscan_on && !iscan->tsk) { ++ iscan->state = WL_ISCAN_STATE_IDLE; ++ sema_init(&iscan->sync, 0); ++ iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan"); ++ if (IS_ERR(iscan->tsk)) { ++ AP6211_ERR("Could not create iscan thread\n"); ++ iscan->tsk = NULL; ++ return -ENOMEM; ++ } ++ } ++ ++ return err; ++} ++ ++static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan) ++{ ++ memset(iscan->iscan_handler, 0, sizeof(iscan->iscan_handler)); ++ iscan->iscan_handler[WL_SCAN_RESULTS_SUCCESS] = wl_iscan_done; ++ iscan->iscan_handler[WL_SCAN_RESULTS_PARTIAL] = wl_iscan_inprogress; ++ iscan->iscan_handler[WL_SCAN_RESULTS_PENDING] = wl_iscan_pending; ++ iscan->iscan_handler[WL_SCAN_RESULTS_ABORTED] = wl_iscan_aborted; ++ iscan->iscan_handler[WL_SCAN_RESULTS_NO_MEM] = wl_iscan_aborted; ++} ++ ++static s32 ++wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, ++ unsigned long state, ++ void *ndev) ++{ ++ struct net_device *dev = ndev; ++ struct wireless_dev *wdev = dev->ieee80211_ptr; ++ struct wl_priv *wl = wlcfg_drv_priv; ++ int refcnt = 0; ++ ++ AP6211_DEBUG("Enter \n"); ++ if (!wdev || !wl || dev == wl_to_prmry_ndev(wl)) ++ return NOTIFY_DONE; ++ switch (state) { ++ case NETDEV_DOWN: ++ while (work_pending(&wdev->cleanup_work) && refcnt < 100) { ++ if (refcnt%5 == 0) ++ AP6211_ERR("%s : [NETDEV_DOWN] work_pending (%d th)\n", ++ __FUNCTION__, refcnt); ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(100); ++ set_current_state(TASK_RUNNING); ++ refcnt++; ++ } ++ break; ++ ++ case NETDEV_UNREGISTER: ++ /* after calling list_del_rcu(&wdev->list) */ ++ wl_dealloc_netinfo(wl, ndev); ++ break; ++ case NETDEV_GOING_DOWN: ++ /* At NETDEV_DOWN state, wdev_cleanup_work work will be called. ++ * In front of door, the function checks ++ * whether current scan is working or not. ++ * If the scanning is still working, wdev_cleanup_work call WARN_ON and ++ * make the scan done forcibly. ++ */ ++ if (wl_get_drv_status(wl, SCANNING, dev)) { ++ if (wl->escan_on) { ++ wl_notify_escan_complete(wl, dev, true, true); ++ } ++ } ++ break; ++ } ++ return NOTIFY_DONE; ++} ++static struct notifier_block wl_cfg80211_netdev_notifier = { ++ .notifier_call = wl_cfg80211_netdev_notifier_call, ++}; ++ ++static s32 wl_notify_escan_complete(struct wl_priv *wl, ++ struct net_device *ndev, ++ bool aborted, bool fw_abort) ++{ ++ wl_scan_params_t *params = NULL; ++ s32 params_size = 0; ++ s32 err = BCME_OK; ++ unsigned long flags; ++ struct net_device *dev; ++ ++ AP6211_DEBUG("Enter \n"); ++ ++ if (wl->escan_info.ndev != ndev) ++ { ++ AP6211_ERR("ndev is different %p %p\n", wl->escan_info.ndev, ndev); ++ return err; ++ } ++ ++ if (wl->scan_request) { ++ if (wl->scan_request->dev == wl->p2p_net) ++ dev = wl_to_prmry_ndev(wl); ++ else ++ dev = wl->scan_request->dev; ++ } ++ else { ++ AP6211_DEBUG("wl->scan_request is NULL may be internal scan." ++ "doing scan_abort for ndev %p primary %p p2p_net %p", ++ ndev, wl_to_prmry_ndev(wl), wl->p2p_net); ++ dev = ndev; ++ } ++ if (fw_abort && !in_atomic()) { ++ /* Our scan params only need space for 1 channel and 0 ssids */ ++ params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size); ++ if (params == NULL) { ++ AP6211_ERR("scan params allocation failed \n"); ++ err = -ENOMEM; ++ } else { ++ /* Do a scan abort to stop the driver's scan engine */ ++ err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true); ++ if (err < 0) { ++ AP6211_ERR("scan abort failed \n"); ++ } ++ } ++ } ++ if (timer_pending(&wl->scan_timeout)) ++ del_timer_sync(&wl->scan_timeout); ++#if defined(ESCAN_RESULT_PATCH) ++ if (likely(wl->scan_request)) { ++ wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; ++ wl_inform_bss(wl); ++ } ++#endif /* ESCAN_RESULT_PATCH */ ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++#ifdef WL_SCHED_SCAN ++ if (wl->sched_scan_req && !wl->scan_request) { ++ AP6211_DEBUG(">>> REPORTING SCHED SCAN RESULTS \n"); ++ if (aborted) ++ cfg80211_sched_scan_stopped(wl->sched_scan_req->wiphy); ++ else ++ cfg80211_sched_scan_results(wl->sched_scan_req->wiphy); ++ wl->sched_scan_running = FALSE; ++ wl->sched_scan_req = NULL; ++ } ++#endif /* WL_SCHED_SCAN */ ++ if (likely(wl->scan_request)) { ++ cfg80211_scan_done(wl->scan_request, aborted); ++ wl->scan_request = NULL; ++ } ++ if (p2p_is_on(wl)) ++ wl_clr_p2p_status(wl, SCANNING); ++ wl_clr_drv_status(wl, SCANNING, dev); ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ if (params) ++ kfree(params); ++ ++ return err; ++} ++ ++static s32 wl_escan_handler(struct wl_priv *wl, ++ struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ s32 err = BCME_OK; ++ s32 status = ntoh32(e->status); ++ wl_bss_info_t *bi; ++ wl_escan_result_t *escan_result; ++ wl_bss_info_t *bss = NULL; ++ wl_scan_results_t *list; ++ wifi_p2p_ie_t * p2p_ie; ++ u32 bi_length; ++ u32 i; ++ u8 *p2p_dev_addr = NULL; ++ ++ AP6211_DEBUG(" enter event type : %d, status : %d \n", ++ ntoh32(e->event_type), ntoh32(e->status)); ++ ++ mutex_lock(&wl->usr_sync); ++ /* P2P SCAN is coming from primary interface */ ++ if (wl_get_p2p_status(wl, SCANNING)) { ++ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) ++ ndev = wl->afx_hdl->dev; ++ else ++ ndev = wl->escan_info.ndev; ++ ++ } ++ if (!ndev || !wl->escan_on || ++ (!wl_get_drv_status(wl, SCANNING, ndev) && ++ !wl->sched_scan_running)) { ++ AP6211_ERR("escan is not ready ndev %p wl->escan_on %d drv_status 0x%x\n", ++ ndev, wl->escan_on, wl_get_drv_status(wl, SCANNING, ndev)); ++ goto exit; ++ } ++ if (status == WLC_E_STATUS_PARTIAL) { ++ AP6211_DEBUG("WLC_E_STATUS_PARTIAL \n"); ++ escan_result = (wl_escan_result_t *) data; ++ if (!escan_result) { ++ AP6211_ERR("Invalid escan result (NULL pointer)\n"); ++ goto exit; ++ } ++ if (dtoh16(escan_result->bss_count) != 1) { ++ AP6211_ERR("Invalid bss_count %d: ignoring\n", escan_result->bss_count); ++ goto exit; ++ } ++ bi = escan_result->bss_info; ++ if (!bi) { ++ AP6211_ERR("Invalid escan bss info (NULL pointer)\n"); ++ goto exit; ++ } ++ bi_length = dtoh32(bi->length); ++ if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) { ++ AP6211_ERR("Invalid bss_info length %d: ignoring\n", bi_length); ++ goto exit; ++ } ++ ++ if (!(wl_to_wiphy(wl)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) { ++ if (dtoh16(bi->capability) & DOT11_CAP_IBSS) { ++ AP6211_DEBUG("Ignoring IBSS result\n"); ++ goto exit; ++ } ++ } ++ ++ if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { ++ p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length); ++ if (p2p_dev_addr && !memcmp(p2p_dev_addr, ++ wl->afx_hdl->tx_dst_addr.octet, ETHER_ADDR_LEN)) { ++ s32 channel = CHSPEC_CHANNEL( ++ wl_chspec_driver_to_host(bi->chanspec)); ++ AP6211_DEBUG("ACTION FRAME SCAN : Peer " MACDBG " found, channel : %d\n", ++ MAC2STRDBG(wl->afx_hdl->tx_dst_addr.octet), channel); ++ wl_clr_p2p_status(wl, SCANNING); ++ wl->afx_hdl->peer_chan = channel; ++ complete(&wl->act_frm_scan); ++ goto exit; ++ } ++ ++ } else { ++ int cur_len = WL_SCAN_RESULTS_FIXED_SIZE; ++ list = (wl_scan_results_t *)wl->escan_info.escan_buf; ++#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) ++ if (wl->p2p_net && wl->scan_request && ++ wl->scan_request->dev == wl->p2p_net) ++#else ++ if (p2p_is_on(wl) && p2p_scan(wl)) ++#endif ++ { ++#ifdef WL_HOST_BAND_MGMT ++ s32 channel = 0; ++ s32 channel_band = 0; ++#endif /* WL_HOST_BAND_MGMT */ ++ /* p2p scan && allow only probe response */ ++ if (bi->flags & WL_BSS_FLAGS_FROM_BEACON) ++ goto exit; ++ if ((p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, ++ bi->ie_length)) == NULL) { ++ AP6211_ERR("Couldn't find P2PIE in probe" ++ " response/beacon\n"); ++ goto exit; ++ } ++#ifdef WL_HOST_BAND_MGMT ++ channel = CHSPEC_CHANNEL(wl_chspec_driver_to_host(bi->chanspec)); ++ channel_band = (channel > CH_MAX_2G_CHANNEL) ? ++ WLC_BAND_5G : WLC_BAND_2G; ++ ++ ++ if ((wl->curr_band == WLC_BAND_5G) && ++ (channel_band == WLC_BAND_2G)) { ++ /* Avoid sending the GO results in band conflict */ ++ if (wl_cfgp2p_retreive_p2pattrib(p2p_ie, ++ P2P_SEID_GROUP_ID) != NULL) ++ goto exit; ++ } ++#endif /* WL_HOST_BAND_MGMT */ ++ } ++ for (i = 0; i < list->count; i++) { ++ bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) ++ : list->bss_info; ++ ++ if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) && ++ (CHSPEC_BAND(wl_chspec_driver_to_host(bi->chanspec)) ++ == CHSPEC_BAND(wl_chspec_driver_to_host(bss->chanspec))) && ++ bi->SSID_len == bss->SSID_len && ++ !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) { ++ ++ /* do not allow beacon data to update ++ *the data recd from a probe response ++ */ ++ if (!(bss->flags & WL_BSS_FLAGS_FROM_BEACON) && ++ (bi->flags & WL_BSS_FLAGS_FROM_BEACON)) ++ goto exit; ++ ++ AP6211_DEBUG("%s("MACDBG"), i=%d prev: RSSI %d" ++ " flags 0x%x, new: RSSI %d flags 0x%x\n", ++ bss->SSID, MAC2STRDBG(bi->BSSID.octet), i, ++ bss->RSSI, bss->flags, bi->RSSI, bi->flags); ++ ++ if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == ++ (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) { ++ /* preserve max RSSI if the measurements are ++ * both on-channel or both off-channel ++ */ ++ AP6211_DEBUG("%s("MACDBG"), same onchan" ++ ", RSSI: prev %d new %d\n", ++ bss->SSID, MAC2STRDBG(bi->BSSID.octet), ++ bss->RSSI, bi->RSSI); ++ bi->RSSI = MAX(bss->RSSI, bi->RSSI); ++ } else if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) && ++ (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) { ++ /* preserve the on-channel rssi measurement ++ * if the new measurement is off channel ++ */ ++ AP6211_DEBUG("%s("MACDBG"), prev onchan" ++ ", RSSI: prev %d new %d\n", ++ bss->SSID, MAC2STRDBG(bi->BSSID.octet), ++ bss->RSSI, bi->RSSI); ++ bi->RSSI = bss->RSSI; ++ bi->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL; ++ } ++ if (dtoh32(bss->length) != bi_length) { ++ u32 prev_len = dtoh32(bss->length); ++ ++ AP6211_DEBUG("bss info replacement" ++ " is occured(bcast:%d->probresp%d)\n", ++ bss->ie_length, bi->ie_length); ++ AP6211_DEBUG("%s("MACDBG"), replacement!(%d -> %d)\n", ++ bss->SSID, MAC2STRDBG(bi->BSSID.octet), ++ prev_len, bi_length); ++ ++ if (list->buflen - prev_len + bi_length ++ > ESCAN_BUF_SIZE) { ++ AP6211_ERR("Buffer is too small: keep the" ++ " previous result of this AP\n"); ++ /* Only update RSSI */ ++ bss->RSSI = bi->RSSI; ++ bss->flags |= (bi->flags ++ & WL_BSS_FLAGS_RSSI_ONCHANNEL); ++ goto exit; ++ } ++ ++ if (i < list->count - 1) { ++ /* memory copy required by this case only */ ++ memmove((u8 *)bss + bi_length, ++ (u8 *)bss + prev_len, ++ list->buflen - cur_len - prev_len); ++ } ++ list->buflen -= prev_len; ++ list->buflen += bi_length; ++ } ++ list->version = dtoh32(bi->version); ++ memcpy((u8 *)bss, (u8 *)bi, bi_length); ++ goto exit; ++ } ++ cur_len += dtoh32(bss->length); ++ } ++ if (bi_length > ESCAN_BUF_SIZE - list->buflen) { ++ AP6211_ERR("Buffer is too small: ignoring\n"); ++ goto exit; ++ } ++ if (strlen(bi->SSID) == 0) { // terence: fix for hidden SSID ++ AP6211_DEBUG("Skip hidden SSID %pM\n", &bi->BSSID); ++ goto exit; ++ } ++ memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length); ++ list->version = dtoh32(bi->version); ++ list->buflen += bi_length; ++ list->count++; ++ } ++ ++ } ++ else if (status == WLC_E_STATUS_SUCCESS) { ++ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; ++ if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { ++ AP6211_DEBUG("ACTION FRAME SCAN DONE\n"); ++ wl_clr_p2p_status(wl, SCANNING); ++ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); ++ if (wl->afx_hdl->peer_chan == WL_INVALID) ++ complete(&wl->act_frm_scan); ++ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { ++ AP6211_DEBUG("ESCAN COMPLETED\n"); ++ wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; ++ wl_inform_bss(wl); ++ wl_notify_escan_complete(wl, ndev, false, false); ++ } ++ } ++ else if (status == WLC_E_STATUS_ABORT) { ++ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; ++ if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { ++ AP6211_DEBUG("ACTION FRAME SCAN DONE\n"); ++ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); ++ wl_clr_p2p_status(wl, SCANNING); ++ if (wl->afx_hdl->peer_chan == WL_INVALID) ++ complete(&wl->act_frm_scan); ++ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { ++ AP6211_DEBUG("ESCAN ABORTED\n"); ++ wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; ++ wl_inform_bss(wl); ++ wl_notify_escan_complete(wl, ndev, true, false); ++ } ++ } ++ else if (status == WLC_E_STATUS_NEWSCAN) ++ { ++ escan_result = (wl_escan_result_t *) data; ++ AP6211_ERR("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", wl->scan_request); ++ AP6211_ERR("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, ++ escan_result->bss_count); ++ } else if (status == WLC_E_STATUS_TIMEOUT) { ++ AP6211_ERR("WLC_E_STATUS_TIMEOUT : scan_request[%p]\n", wl->scan_request); ++ AP6211_ERR("escan_on[%d], reason[0x%x]\n", wl->escan_on, e->reason); ++ if (e->reason == 0xFFFFFFFF) { ++ wl_notify_escan_complete(wl, wl->escan_info.ndev, true, true); ++ } ++ } else { ++ AP6211_ERR("unexpected Escan Event %d : abort\n", status); ++ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; ++ if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { ++ AP6211_DEBUG("ACTION FRAME SCAN DONE\n"); ++ wl_clr_p2p_status(wl, SCANNING); ++ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); ++ if (wl->afx_hdl->peer_chan == WL_INVALID) ++ complete(&wl->act_frm_scan); ++ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { ++ wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; ++ wl_inform_bss(wl); ++ wl_notify_escan_complete(wl, ndev, true, false); ++ } ++ } ++exit: ++ mutex_unlock(&wl->usr_sync); ++ return err; ++} ++static void wl_cfg80211_concurrent_roam(struct wl_priv *wl, int enable) ++{ ++ u32 connected_cnt = wl_get_drv_status_all(wl, CONNECTED); ++ struct net_info *iter, *next; ++ int err; ++ ++ if (!wl->roamoff_on_concurrent) ++ return; ++ if (enable && connected_cnt > 1) { ++ for_each_ndev(wl, iter, next) { ++ /* Save the current roam setting */ ++ if ((err = wldev_iovar_getint(iter->ndev, "roam_off", ++ (s32 *)&iter->roam_off)) != BCME_OK) { ++ AP6211_ERR("%s:Failed to get current roam setting err %d\n", ++ iter->ndev->name, err); ++ continue; ++ } ++ if ((err = wldev_iovar_setint(iter->ndev, "roam_off", 1)) != BCME_OK) { ++ AP6211_ERR(" %s:failed to set roam_off : %d\n", ++ iter->ndev->name, err); ++ } ++ } ++ } ++ else if (!enable) { ++ for_each_ndev(wl, iter, next) { ++ if (iter->roam_off != WL_INVALID) { ++ if ((err = wldev_iovar_setint(iter->ndev, "roam_off", ++ iter->roam_off)) == BCME_OK) ++ iter->roam_off = WL_INVALID; ++ else { ++ AP6211_ERR(" %s:failed to set roam_off : %d\n", ++ iter->ndev->name, err); ++ } ++ } ++ } ++ } ++ return; ++} ++ ++static void wl_cfg80211_determine_vsdb_mode(struct wl_priv *wl) ++{ ++ struct net_info *iter, *next; ++ u32 chan = 0; ++ u32 chanspec = 0; ++ u32 prev_chan = 0; ++ u32 connected_cnt = wl_get_drv_status_all(wl, CONNECTED); ++ wl->vsdb_mode = false; ++ ++ if (connected_cnt <= 1) { ++ return; ++ } ++ for_each_ndev(wl, iter, next) { ++ chanspec = 0; ++ chan = 0; ++ if (wl_get_drv_status(wl, CONNECTED, iter->ndev)) { ++ if (wldev_iovar_getint(iter->ndev, "chanspec", ++ (s32 *)&chanspec) == BCME_OK) { ++ chan = CHSPEC_CHANNEL(chanspec); ++ if (CHSPEC_IS40(chanspec)) { ++ if (CHSPEC_SB_UPPER(chanspec)) ++ chan += CH_10MHZ_APART; ++ else ++ chan -= CH_10MHZ_APART; ++ } ++ wl_update_prof(wl, iter->ndev, NULL, ++ &chan, WL_PROF_CHAN); ++ } ++ if (!prev_chan && chan) ++ prev_chan = chan; ++ else if (prev_chan && (prev_chan != chan)) ++ wl->vsdb_mode = true; ++ } ++ } ++ return; ++} ++static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_info, ++ enum wl_status state, bool set) ++{ ++ s32 pm = PM_FAST; ++ s32 err = BCME_OK; ++ u32 chan = 0; ++ struct net_info *iter, *next; ++ struct net_device *primary_dev = wl_to_prmry_ndev(wl); ++ AP6211_DEBUG("Enter state %d set %d _net_info->pm_restore %d iface %s\n", ++ state, set, _net_info->pm_restore, _net_info->ndev->name); ++ ++ if (state != WL_STATUS_CONNECTED) ++ return 0; ++ ++ if (set) { ++ wl_cfg80211_concurrent_roam(wl, 1); ++ ++ if (wl_get_mode_by_netdev(wl, _net_info->ndev) == WL_MODE_AP) { ++ pm = PM_OFF; ++ AP6211_DEBUG("%s:AP power save %s\n", _net_info->ndev->name, ++ pm ? "enabled" : "disabled"); ++ if ((err = wldev_ioctl(_net_info->ndev, WLC_SET_PM, ++ &pm, sizeof(pm), true)) != 0) { ++ if (err == -ENODEV) ++ AP6211_DEBUG("%s:net_device is not ready\n", ++ _net_info->ndev->name); ++ else ++ AP6211_ERR("%s:error (%d)\n", _net_info->ndev->name, err); ++ } ++ if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false)) ++ AP6211_ERR(" failed to unset WLC_E_P2P_PROPREQ_MSG\n"); ++ return 0; ++ } ++ wl_cfg80211_determine_vsdb_mode(wl); ++ pm = PM_OFF; ++ for_each_ndev(wl, iter, next) { ++ if ((!wl->vsdb_mode) && (iter->ndev != _net_info->ndev)) { ++ /* Do not touch the other interfaces power save ++ * if we are not in vsdb mode ++ */ ++ continue; ++ } ++ /* Save the current power mode */ ++ iter->pm_restore = true; ++ err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm, ++ sizeof(iter->pm), false); ++ AP6211_DEBUG("%s:power save %s\n", iter->ndev->name, ++ iter->pm ? "enabled" : "disabled"); ++ if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm, ++ sizeof(pm), true)) != 0) { ++ if (err == -ENODEV) ++ AP6211_DEBUG("%s:netdev not ready\n", iter->ndev->name); ++ else ++ AP6211_ERR("%s:error (%d)\n", iter->ndev->name, err); ++ iter->ndev->ieee80211_ptr->ps = pm ? true: false; ++ } ++ } ++ } ++ else { /* clear */ ++ chan = 0; ++ /* clear chan information when the net device is disconnected */ ++ wl_update_prof(wl, _net_info->ndev, NULL, &chan, WL_PROF_CHAN); ++ wl_cfg80211_determine_vsdb_mode(wl); ++ for_each_ndev(wl, iter, next) { ++ if (iter->pm_restore) { ++ AP6211_DEBUG("%s:restoring power save %s\n", ++ iter->ndev->name, (iter->pm ? "enabled" : "disabled")); ++ err = wldev_ioctl(iter->ndev, ++ WLC_SET_PM, &iter->pm, sizeof(iter->pm), true); ++ if (unlikely(err)) { ++ if (err == -ENODEV) ++ AP6211_DEBUG("%s:netdev not ready\n", iter->ndev->name); ++ else ++ AP6211_ERR("%s:error(%d)\n", iter->ndev->name, err); ++ break; ++ } ++ iter->pm_restore = 0; ++ } ++ } ++ wl_cfg80211_concurrent_roam(wl, 0); ++ } ++ return err; ++} ++ ++static s32 wl_init_scan(struct wl_priv *wl) ++{ ++ struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); ++ int err = 0; ++ ++ if (wl->iscan_on) { ++ iscan->dev = wl_to_prmry_ndev(wl); ++ iscan->state = WL_ISCAN_STATE_IDLE; ++ wl_init_iscan_handler(iscan); ++ iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS; ++ init_timer(&iscan->timer); ++ iscan->timer.data = (unsigned long) iscan; ++ iscan->timer.function = wl_iscan_timer; ++ sema_init(&iscan->sync, 0); ++ iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan"); ++ if (IS_ERR(iscan->tsk)) { ++ AP6211_ERR("Could not create iscan thread\n"); ++ iscan->tsk = NULL; ++ return -ENOMEM; ++ } ++ iscan->data = wl; ++ } else if (wl->escan_on) { ++ wl->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler; ++ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; ++ } ++ /* Init scan_timeout timer */ ++ init_timer(&wl->scan_timeout); ++ wl->scan_timeout.data = (unsigned long) wl; ++ wl->scan_timeout.function = wl_scan_timeout; ++ ++ return err; ++} ++ ++static s32 wl_init_priv(struct wl_priv *wl) ++{ ++ struct wiphy *wiphy = wl_to_wiphy(wl); ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ s32 err = 0; ++ ++ wl->scan_request = NULL; ++ wl->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT); ++ wl->iscan_on = false; ++ wl->escan_on = true; ++ wl->roam_on = false; ++ wl->iscan_kickstart = false; ++ wl->active_scan = true; ++ wl->rf_blocked = false; ++ wl->vsdb_mode = false; ++ wl->wlfc_on = false; ++ wl->roamoff_on_concurrent = true; ++ /* register interested state */ ++ set_bit(WL_STATUS_CONNECTED, &wl->interrested_state); ++ spin_lock_init(&wl->cfgdrv_lock); ++ mutex_init(&wl->ioctl_buf_sync); ++ init_waitqueue_head(&wl->netif_change_event); ++ init_completion(&wl->send_af_done); ++ init_completion(&wl->iface_disable); ++ wl_init_eq(wl); ++ err = wl_init_priv_mem(wl); ++ if (err) ++ return err; ++ if (wl_create_event_handler(wl)) ++ return -ENOMEM; ++ wl_init_event_handler(wl); ++ mutex_init(&wl->usr_sync); ++ mutex_init(&wl->event_sync); ++ err = wl_init_scan(wl); ++ if (err) ++ return err; ++ wl_init_conf(wl->conf); ++ wl_init_prof(wl, ndev); ++ wl_link_down(wl); ++ DNGL_FUNC(dhd_cfg80211_init, (wl)); ++ ++ return err; ++} ++ ++static void wl_deinit_priv(struct wl_priv *wl) ++{ ++ DNGL_FUNC(dhd_cfg80211_deinit, (wl)); ++ wl_destroy_event_handler(wl); ++ wl_flush_eq(wl); ++ wl_link_down(wl); ++ del_timer_sync(&wl->scan_timeout); ++ wl_term_iscan(wl); ++ wl_deinit_priv_mem(wl); ++ unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier); ++} ++ ++#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) ++static s32 wl_cfg80211_attach_p2p(void) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ ++ AP6211_DEBUG("Enter \n"); ++ ++ if (wl_cfgp2p_register_ndev(wl) < 0) { ++ AP6211_ERR("%s: P2P attach failed. \n", __func__); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static s32 wl_cfg80211_detach_p2p(void) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct wireless_dev *wdev = wl->p2p_wdev; ++ ++ AP6211_DEBUG("Enter \n"); ++ if (!wdev || !wl) { ++ AP6211_ERR("Invalid Ptr\n"); ++ return -EINVAL; ++ } ++ ++ wl_cfgp2p_unregister_ndev(wl); ++ ++ wl->p2p_wdev = NULL; ++ wl->p2p_net = NULL; ++ AP6211_DEBUG("Freeing 0x%08x \n", (unsigned int)wdev); ++ kfree(wdev); ++ ++ return 0; ++} ++#endif /* defined(WLP2P) && defined(WL_ENABLE_P2P_IF) */ ++ ++s32 wl_cfg80211_attach_post(struct net_device *ndev) ++{ ++ struct wl_priv * wl = NULL; ++ s32 err = 0; ++ AP6211_DEBUG("In\n"); ++ if (unlikely(!ndev)) { ++ AP6211_ERR("ndev is invaild\n"); ++ return -ENODEV; ++ } ++ wl = wlcfg_drv_priv; ++ if (unlikely(!wl)) { ++ AP6211_ERR("wl is invaild\n"); ++ return -EINVAL; ++ } ++ if (!wl_get_drv_status(wl, READY, ndev)) { ++ if (wl->wdev && ++ wl_cfgp2p_supported(wl, ndev)) { ++#if !defined(WL_ENABLE_P2P_IF) ++ wl->wdev->wiphy->interface_modes |= ++ (BIT(NL80211_IFTYPE_P2P_CLIENT)| ++ BIT(NL80211_IFTYPE_P2P_GO)); ++#endif ++ if ((err = wl_cfgp2p_init_priv(wl)) != 0) ++ goto fail; ++ ++#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) ++ if (wl->p2p_net) { ++ /* Update MAC addr for p2p0 interface here. */ ++ memcpy(wl->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN); ++ wl->p2p_net->dev_addr[0] |= 0x02; ++ AP6211_ERR("%s: p2p_dev_addr="MACDBG "\n", ++ wl->p2p_net->name, ++ MAC2STRDBG(wl->p2p_net->dev_addr)); ++ } else { ++ AP6211_ERR("p2p_net not yet populated." ++ " Couldn't update the MAC Address for p2p0 \n"); ++ return -ENODEV; ++ } ++#endif /* defined(WLP2P) && (WL_ENABLE_P2P_IF) */ ++ ++ wl->p2p_supported = true; ++ } ++ } ++ wl_set_drv_status(wl, READY, ndev); ++fail: ++ return err; ++} ++ ++s32 wl_cfg80211_attach(struct net_device *ndev, void *data) ++{ ++ struct wireless_dev *wdev; ++ struct wl_priv *wl; ++ s32 err = 0; ++ struct device *dev; ++ ++ AP6211_DEBUG("In\n"); ++ if (!ndev) { ++ AP6211_ERR("ndev is invaild\n"); ++ return -ENODEV; ++ } ++ AP6211_DEBUG("func %p\n", wl_cfg80211_get_parent_dev()); ++ dev = wl_cfg80211_get_parent_dev(); ++ ++ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); ++ if (unlikely(!wdev)) { ++ AP6211_ERR("Could not allocate wireless device\n"); ++ return -ENOMEM; ++ } ++ err = wl_setup_wiphy(wdev, dev); ++ if (unlikely(err)) { ++ kfree(wdev); ++ return -ENOMEM; ++ } ++ wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); ++ wl = (struct wl_priv *)wiphy_priv(wdev->wiphy); ++ wl->wdev = wdev; ++ wl->pub = data; ++ INIT_LIST_HEAD(&wl->net_list); ++ ndev->ieee80211_ptr = wdev; ++ SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); ++ wdev->netdev = ndev; ++ wl->state_notifier = wl_notifier_change_state; ++ err = wl_alloc_netinfo(wl, ndev, wdev, WL_MODE_BSS, PM_ENABLE); ++ if (err) { ++ AP6211_ERR("Failed to alloc net_info (%d)\n", err); ++ goto cfg80211_attach_out; ++ } ++ err = wl_init_priv(wl); ++ if (err) { ++ AP6211_ERR("Failed to init iwm_priv (%d)\n", err); ++ goto cfg80211_attach_out; ++ } ++ ++ err = wl_setup_rfkill(wl, TRUE); ++ if (err) { ++ AP6211_ERR("Failed to setup rfkill %d\n", err); ++ goto cfg80211_attach_out; ++ } ++ err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier); ++ if (err) { ++ AP6211_ERR("Failed to register notifierl %d\n", err); ++ goto cfg80211_attach_out; ++ } ++#if defined(COEX_DHCP) ++ if (wl_cfg80211_btcoex_init(wl)) ++ goto cfg80211_attach_out; ++#endif ++#if defined(BSSCACHE) ++ wl_init_bss_cache_ctrl(&g_bss_cache_ctrl); ++#endif ++ ++ wlcfg_drv_priv = wl; ++ ++#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) ++ err = wl_cfg80211_attach_p2p(); ++ if (err) ++ goto cfg80211_attach_out; ++#endif ++ ++ return err; ++ ++cfg80211_attach_out: ++ err = wl_setup_rfkill(wl, FALSE); ++ wl_free_wdev(wl); ++ return err; ++} ++ ++void wl_cfg80211_detach(void *para) ++{ ++ struct wl_priv *wl; ++ ++ (void)para; ++ wl = wlcfg_drv_priv; ++ ++ AP6211_DEBUG("In\n"); ++ ++#if defined(COEX_DHCP) ++ wl_cfg80211_btcoex_deinit(wl); ++#endif ++ ++ wl_setup_rfkill(wl, FALSE); ++ if (wl->p2p_supported) { ++ if (timer_pending(&wl->p2p->listen_timer)) ++ del_timer_sync(&wl->p2p->listen_timer); ++ wl_cfgp2p_deinit_priv(wl); ++ } ++ ++#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) ++ wl_cfg80211_detach_p2p(); ++#endif ++ wl_deinit_priv(wl); ++ wlcfg_drv_priv = NULL; ++ wl_cfg80211_clear_parent_dev(); ++ wl_free_wdev(wl); ++#if defined(RSSIAVG) ++ wl_free_rssi_cache(&g_rssi_cache_ctrl); ++#endif ++#if defined(BSSCACHE) ++ wl_release_bss_cache_ctrl(&g_bss_cache_ctrl); ++#endif ++ /* PLEASE do NOT call any function after wl_free_wdev, the driver's private structure "wl", ++ * which is the private part of wiphy, has been freed in wl_free_wdev !!!!!!!!!!! ++ */ ++} ++ ++static void wl_wakeup_event(struct wl_priv *wl) ++{ ++ if (wl->event_tsk.thr_pid >= 0) { ++ DHD_OS_WAKE_LOCK(wl->pub); ++ up(&wl->event_tsk.sema); ++ } ++} ++ ++static int wl_is_p2p_event(struct wl_event_q *e) ++{ ++ switch (e->etype) { ++ /* We have to seperate out the P2P events received ++ * on primary interface so that it can be send up ++ * via p2p0 interface. ++ */ ++ case WLC_E_P2P_PROBREQ_MSG: ++ case WLC_E_P2P_DISC_LISTEN_COMPLETE: ++ case WLC_E_ACTION_FRAME_RX: ++ case WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE: ++ case WLC_E_ACTION_FRAME_COMPLETE: ++ ++ if (e->emsg.ifidx != 0) { ++ AP6211_DEBUG("P2P Event on Virtual I/F (ifidx:%d) \n", ++ e->emsg.ifidx); ++ /* We are only bothered about the P2P events received ++ * on primary interface. For rest of them return false ++ * so that it is sent over the interface corresponding ++ * to the ifidx. ++ */ ++ return FALSE; ++ } else { ++ AP6211_DEBUG("P2P Event on Primary I/F (ifidx:%d)." ++ " Sent it to p2p0 \n", e->emsg.ifidx); ++ return TRUE; ++ } ++ break; ++ ++ default: ++ AP6211_DEBUG("NON-P2P Event %d on ifidx (ifidx:%d) \n", ++ e->etype, e->emsg.ifidx); ++ return FALSE; ++ } ++} ++ ++static s32 wl_event_handler(void *data) ++{ ++ struct net_device *netdev; ++ struct wl_priv *wl = NULL; ++ struct wl_event_q *e; ++ tsk_ctl_t *tsk = (tsk_ctl_t *)data; ++ ++ wl = (struct wl_priv *)tsk->parent; ++#ifndef USE_KTHREAD_API ++ DAEMONIZE("dhd_cfg80211_event"); ++ complete(&tsk->completed); ++#else ++ AP6211_ERR("tsk Enter, tsk = 0x%08x\n", (unsigned int)tsk); ++#endif ++ ++ while (down_interruptible (&tsk->sema) == 0) { ++ SMP_RD_BARRIER_DEPENDS(); ++ if (tsk->terminated) ++ break; ++ while ((e = wl_deq_event(wl))) { ++ AP6211_DEBUG("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx); ++ /* All P2P device address related events comes on primary interface since ++ * there is no corresponding bsscfg for P2P interface. Map it to p2p0 ++ * interface. ++ */ ++ if ((wl_is_p2p_event(e) == TRUE) && (wl->p2p_net)) { ++ netdev = wl->p2p_net; ++ } else { ++ netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx); ++ } ++ if (!netdev) ++ netdev = wl_to_prmry_ndev(wl); ++ if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) { ++ wl->evt_handler[e->etype] (wl, netdev, &e->emsg, e->edata); ++ } else { ++ AP6211_DEBUG("Unknown Event (%d): ignoring\n", e->etype); ++ } ++ wl_put_event(e); ++ } ++ DHD_OS_WAKE_UNLOCK(wl->pub); ++ } ++ AP6211_ERR("%s was terminated\n", __func__); ++ complete_and_exit(&tsk->completed, 0); ++ return 0; ++} ++ ++void ++wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) ++{ ++ u32 event_type = ntoh32(e->event_type); ++ struct wl_priv *wl = wlcfg_drv_priv; ++ ++#if (WL_DBG_LEVEL > 0) ++ s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ? ++ wl_dbg_estr[event_type] : (s8 *) "Unknown"; ++ AP6211_DEBUG("event_type (%d):" "WLC_E_" "%s\n", event_type, estr); ++#endif /* (WL_DBG_LEVEL > 0) */ ++ ++ if (event_type == WLC_E_PFN_NET_FOUND) { ++ AP6211_DEBUG(" PNOEVENT: PNO_NET_FOUND\n"); ++ } ++ else if (event_type == WLC_E_PFN_NET_LOST) { ++ AP6211_DEBUG(" PNOEVENT: PNO_NET_LOST\n"); ++ } ++ ++ if (likely(!wl_enq_event(wl, ndev, event_type, e, data))) ++ wl_wakeup_event(wl); ++} ++ ++static void wl_init_eq(struct wl_priv *wl) ++{ ++ wl_init_eq_lock(wl); ++ INIT_LIST_HEAD(&wl->eq_list); ++} ++ ++static void wl_flush_eq(struct wl_priv *wl) ++{ ++ struct wl_event_q *e; ++ unsigned long flags; ++ ++ flags = wl_lock_eq(wl); ++ while (!list_empty(&wl->eq_list)) { ++ e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list); ++ list_del(&e->eq_list); ++ kfree(e); ++ } ++ wl_unlock_eq(wl, flags); ++} ++ ++/* ++* retrieve first queued event from head ++*/ ++ ++static struct wl_event_q *wl_deq_event(struct wl_priv *wl) ++{ ++ struct wl_event_q *e = NULL; ++ unsigned long flags; ++ ++ flags = wl_lock_eq(wl); ++ if (likely(!list_empty(&wl->eq_list))) { ++ e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list); ++ list_del(&e->eq_list); ++ } ++ wl_unlock_eq(wl, flags); ++ ++ return e; ++} ++ ++/* ++ * push event to tail of the queue ++ */ ++ ++static s32 ++wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 event, const wl_event_msg_t *msg, ++ void *data) ++{ ++ struct wl_event_q *e; ++ s32 err = 0; ++ uint32 evtq_size; ++ uint32 data_len; ++ unsigned long flags; ++ gfp_t aflags; ++ ++ data_len = 0; ++ if (data) ++ data_len = ntoh32(msg->datalen); ++ evtq_size = sizeof(struct wl_event_q) + data_len; ++ aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; ++ e = kzalloc(evtq_size, aflags); ++ if (unlikely(!e)) { ++ AP6211_ERR("event alloc failed\n"); ++ return -ENOMEM; ++ } ++ e->etype = event; ++ memcpy(&e->emsg, msg, sizeof(wl_event_msg_t)); ++ if (data) ++ memcpy(e->edata, data, data_len); ++ flags = wl_lock_eq(wl); ++ list_add_tail(&e->eq_list, &wl->eq_list); ++ wl_unlock_eq(wl, flags); ++ ++ return err; ++} ++ ++static void wl_put_event(struct wl_event_q *e) ++{ ++ kfree(e); ++} ++ ++static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype) ++{ ++ s32 infra = 0; ++ s32 err = 0; ++ s32 mode = 0; ++ switch (iftype) { ++ case NL80211_IFTYPE_MONITOR: ++ case NL80211_IFTYPE_WDS: ++ AP6211_ERR("type (%d) : currently we do not support this mode\n", ++ iftype); ++ err = -EINVAL; ++ return err; ++ case NL80211_IFTYPE_ADHOC: ++ mode = WL_MODE_IBSS; ++ break; ++ case NL80211_IFTYPE_STATION: ++ case NL80211_IFTYPE_P2P_CLIENT: ++ mode = WL_MODE_BSS; ++ infra = 1; ++ break; ++ case NL80211_IFTYPE_AP: ++ case NL80211_IFTYPE_P2P_GO: ++ mode = WL_MODE_AP; ++ infra = 1; ++ break; ++ default: ++ err = -EINVAL; ++ AP6211_ERR("invalid type (%d)\n", iftype); ++ return err; ++ } ++ infra = htod32(infra); ++ err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true); ++ if (unlikely(err)) { ++ AP6211_ERR("WLC_SET_INFRA error (%d)\n", err); ++ return err; ++ } ++ ++ wl_set_mode_by_netdev(wl, ndev, mode); ++ ++ return 0; ++} ++ ++void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf *ev, u16 event, bool set) ++{ ++ if (!ev || (event > WLC_E_LAST)) ++ return; ++ ++ if (ev->num < MAX_EVENT_BUF_NUM) { ++ ev->event[ev->num].type = event; ++ ev->event[ev->num].set = set; ++ ev->num++; ++ } else { ++ AP6211_ERR("evenbuffer doesn't support > %u events. Update" ++ " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM); ++ ASSERT(0); ++ } ++} ++ ++s32 wl_cfg80211_apply_eventbuffer( ++ struct net_device *ndev, ++ struct wl_priv *wl, ++ wl_eventmsg_buf_t *ev) ++{ ++ char eventmask[WL_EVENTING_MASK_LEN]; ++ int i, ret = 0; ++ s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; ++ ++ if (!ev || (!ev->num)) ++ return -EINVAL; ++ ++ mutex_lock(&wl->event_sync); ++ ++ /* Read event_msgs mask */ ++ bcm_mkiovar("event_msgs", NULL, 0, iovbuf, ++ sizeof(iovbuf)); ++ ret = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false); ++ if (unlikely(ret)) { ++ AP6211_ERR("Get event_msgs error (%d)\n", ret); ++ goto exit; ++ } ++ memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); ++ ++ /* apply the set bits */ ++ for (i = 0; i < ev->num; i++) { ++ if (ev->event[i].set) ++ setbit(eventmask, ev->event[i].type); ++ else ++ clrbit(eventmask, ev->event[i].type); ++ } ++ ++ /* Write updated Event mask */ ++ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, ++ sizeof(iovbuf)); ++ ret = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); ++ if (unlikely(ret)) { ++ AP6211_ERR("Set event_msgs error (%d)\n", ret); ++ } ++ ++exit: ++ mutex_unlock(&wl->event_sync); ++ return ret; ++} ++ ++s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add) ++{ ++ s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; ++ s8 eventmask[WL_EVENTING_MASK_LEN]; ++ s32 err = 0; ++ struct wl_priv *wl = wlcfg_drv_priv; ++ ++ if (!ndev || !wl) ++ return -ENODEV; ++ ++ mutex_lock(&wl->event_sync); ++ ++ /* Setup event_msgs */ ++ bcm_mkiovar("event_msgs", NULL, 0, iovbuf, ++ sizeof(iovbuf)); ++ err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false); ++ if (unlikely(err)) { ++ AP6211_ERR("Get event_msgs error (%d)\n", err); ++ goto eventmsg_out; ++ } ++ memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); ++ if (add) { ++ setbit(eventmask, event); ++ } else { ++ clrbit(eventmask, event); ++ } ++ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, ++ sizeof(iovbuf)); ++ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); ++ if (unlikely(err)) { ++ AP6211_ERR("Set event_msgs error (%d)\n", err); ++ goto eventmsg_out; ++ } ++ ++eventmsg_out: ++ mutex_unlock(&wl->event_sync); ++ return err; ++} ++ ++static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap) ++{ ++ struct net_device *dev = wl_to_prmry_ndev(wl); ++ struct ieee80211_channel *band_chan_arr = NULL; ++ wl_uint32_list_t *list; ++ u32 i, j, index, n_2g, n_5g, band, channel, array_size; ++ u32 *n_cnt = NULL; ++ chanspec_t c = 0; ++ s32 err = BCME_OK; ++ bool update; ++ bool ht40_allowed; ++ u8 *pbuf = NULL; ++ ++#define LOCAL_BUF_LEN 1024 ++ pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL); ++ ++ if (pbuf == NULL) { ++ AP6211_ERR("failed to allocate local buf\n"); ++ return -ENOMEM; ++ } ++ list = (wl_uint32_list_t *)(void *) pbuf; ++ list->count = htod32(WL_NUMCHANSPECS); ++ ++ ++ err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, ++ 0, pbuf, LOCAL_BUF_LEN, 0, &wl->ioctl_buf_sync); ++ if (err != 0) { ++ AP6211_ERR("get chanspecs failed with %d\n", err); ++ kfree(pbuf); ++ return err; ++ } ++#undef LOCAL_BUF_LEN ++ ++ list = (wl_uint32_list_t *)(void *)pbuf; ++ band = array_size = n_2g = n_5g = 0; ++ for (i = 0; i < dtoh32(list->count); i++) { ++ index = 0; ++ update = false; ++ ht40_allowed = false; ++ c = (chanspec_t)dtoh32(list->element[i]); ++ c = wl_chspec_driver_to_host(c); ++ channel = CHSPEC_CHANNEL(c); ++ if (CHSPEC_IS40(c)) { ++ if (CHSPEC_SB_UPPER(c)) ++ channel += CH_10MHZ_APART; ++ else ++ channel -= CH_10MHZ_APART; ++ } else if (CHSPEC_IS80(c)) { ++ AP6211_DEBUG("HT80 center channel : %d\n", channel); ++ continue; ++ } ++ if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) && ++ (channel <= CH_MAX_2G_CHANNEL)) { ++ band_chan_arr = __wl_2ghz_channels; ++ array_size = ARRAYSIZE(__wl_2ghz_channels); ++ n_cnt = &n_2g; ++ band = IEEE80211_BAND_2GHZ; ++ ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false; ++ } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) { ++ band_chan_arr = __wl_5ghz_a_channels; ++ array_size = ARRAYSIZE(__wl_5ghz_a_channels); ++ n_cnt = &n_5g; ++ band = IEEE80211_BAND_5GHZ; ++ ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true; ++ } else { ++ AP6211_ERR("Invalid channel Sepc. 0x%x.\n", c); ++ continue; ++ } ++ if (!ht40_allowed && CHSPEC_IS40(c)) ++ continue; ++ for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) { ++ if (band_chan_arr[j].hw_value == channel) { ++ update = true; ++ break; ++ } ++ } ++ if (update) ++ index = j; ++ else ++ index = *n_cnt; ++ if (index < array_size) { ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) ++ band_chan_arr[index].center_freq = ++ ieee80211_channel_to_frequency(channel); ++#else ++ band_chan_arr[index].center_freq = ++ ieee80211_channel_to_frequency(channel, band); ++#endif ++ band_chan_arr[index].hw_value = channel; ++ ++ if (CHSPEC_IS40(c) && ht40_allowed) { ++ /* assuming the order is HT20, HT40 Upper, ++ HT40 lower from chanspecs ++ */ ++ u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40; ++ if (CHSPEC_SB_UPPER(c)) { ++ if (ht40_flag == IEEE80211_CHAN_NO_HT40) ++ band_chan_arr[index].flags &= ++ ~IEEE80211_CHAN_NO_HT40; ++ band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS; ++ } else { ++ /* It should be one of ++ IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS ++ */ ++ band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40; ++ if (ht40_flag == IEEE80211_CHAN_NO_HT40) ++ band_chan_arr[index].flags |= ++ IEEE80211_CHAN_NO_HT40MINUS; ++ } ++ } else { ++ band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40; ++ if (band == IEEE80211_BAND_2GHZ) ++ channel |= WL_CHANSPEC_BAND_2G; ++ else ++ channel |= WL_CHANSPEC_BAND_5G; ++ channel |= WL_CHANSPEC_BW_20; ++ channel = wl_chspec_host_to_driver(channel); ++ err = wldev_iovar_getint(dev, "per_chan_info", &channel); ++ if (!err) { ++ if (channel & WL_CHAN_RADAR) ++ band_chan_arr[index].flags |= ++ (IEEE80211_CHAN_RADAR | ++ IEEE80211_CHAN_NO_IBSS); ++ if (channel & WL_CHAN_PASSIVE) ++ band_chan_arr[index].flags |= ++ IEEE80211_CHAN_PASSIVE_SCAN; ++ } ++ } ++ if (!update) ++ (*n_cnt)++; ++ } ++ ++ } ++ __wl_band_2ghz.n_channels = n_2g; ++ __wl_band_5ghz_a.n_channels = n_5g; ++ kfree(pbuf); ++ return err; ++} ++ ++s32 wl_update_wiphybands(struct wl_priv *wl, bool notify) ++{ ++ struct wiphy *wiphy; ++ struct net_device *dev; ++ u32 bandlist[3]; ++ u32 nband = 0; ++ u32 i = 0; ++ s32 err = 0; ++ s32 index = 0; ++ s32 nmode = 0; ++ bool rollback_lock = false; ++ s32 bw_cap = 0; ++ s32 cur_band = -1; ++ struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, }; ++ ++ if (wl == NULL) { ++ wl = wlcfg_drv_priv; ++ mutex_lock(&wl->usr_sync); ++ rollback_lock = true; ++ } ++ dev = wl_to_prmry_ndev(wl); ++ ++ memset(bandlist, 0, sizeof(bandlist)); ++ err = wldev_ioctl(dev, WLC_GET_BANDLIST, bandlist, ++ sizeof(bandlist), false); ++ if (unlikely(err)) { ++ AP6211_ERR("error read bandlist (%d)\n", err); ++ goto end_bands; ++ } ++ ++ wiphy = wl_to_wiphy(wl); ++ ++ err = wldev_ioctl(dev, WLC_GET_BAND, &cur_band, ++ sizeof(s32), false); ++ if (unlikely(err)) { ++ AP6211_ERR("error (%d)\n", err); ++ goto end_bands; ++ } ++ ++ err = wldev_iovar_getint(dev, "nmode", &nmode); ++ if (unlikely(err)) { ++ AP6211_ERR("error reading nmode (%d)\n", err); ++ } else { ++ /* For nmodeonly check bw cap */ ++ err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); ++ if (unlikely(err)) { ++ AP6211_ERR("error get mimo_bw_cap (%d)\n", err); ++ } ++ } ++ ++ err = wl_construct_reginfo(wl, bw_cap); ++ if (err) { ++ AP6211_ERR("wl_construct_reginfo() fails err=%d\n", err); ++ if (err != BCME_UNSUPPORTED) ++ goto end_bands; ++ err = 0; ++ } ++ ++ nband = bandlist[0]; ++ ++ for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) { ++ index = -1; ++ if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) { ++ bands[IEEE80211_BAND_5GHZ] = ++ &__wl_band_5ghz_a; ++ index = IEEE80211_BAND_5GHZ; ++ if (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G) ++ bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; ++ } ++ else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) { ++ bands[IEEE80211_BAND_2GHZ] = ++ &__wl_band_2ghz; ++ index = IEEE80211_BAND_2GHZ; ++ if (bw_cap == WLC_N_BW_40ALL) ++ bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; ++ } ++ ++ if ((index >= 0) && nmode) { ++ bands[index]->ht_cap.cap |= ++ (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40); ++ bands[index]->ht_cap.ht_supported = TRUE; ++ bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; ++ bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; ++ /* An HT shall support all EQM rates for one spatial stream */ ++ bands[index]->ht_cap.mcs.rx_mask[0] = 0xff; ++ } ++ ++ } ++ ++ wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ]; ++ wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ]; ++ ++ if (notify) ++ wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); ++ ++end_bands: ++ if (rollback_lock) ++ mutex_unlock(&wl->usr_sync); ++ return err; ++} ++ ++static s32 __wl_cfg80211_up(struct wl_priv *wl) ++{ ++ s32 err = 0; ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ struct wireless_dev *wdev = ndev->ieee80211_ptr; ++ ++ AP6211_DEBUG("In\n"); ++ ++ err = dhd_config_dongle(wl, false); ++ if (unlikely(err)) ++ return err; ++ ++ err = wl_config_ifmode(wl, ndev, wdev->iftype); ++ if (unlikely(err && err != -EINPROGRESS)) { ++ AP6211_ERR("wl_config_ifmode failed\n"); ++ } ++ err = wl_update_wiphybands(wl, true); ++ if (unlikely(err)) { ++ AP6211_ERR("wl_update_wiphybands failed\n"); ++ } ++ ++ err = dhd_monitor_init(wl->pub); ++ err = wl_invoke_iscan(wl); ++ ++#ifdef WL_HOST_BAND_MGMT ++ /* By default the curr_band is initialized to BAND_AUTO */ ++ if (wl_cfg80211_set_band(ndev, WLC_BAND_AUTO) < 0) { ++ AP6211_ERR("roam_band set failed\n"); ++ err = -1; ++ } ++#endif /* WL_HOST_BAND_MGMT */ ++ ++#if defined(DHCP_SCAN_SUPPRESS) ++ /* wlan scan_supp timer and work thread info */ ++ init_timer(&wl->scan_supp_timer); ++ wl->scan_supp_timer.data = (ulong)wl; ++ wl->scan_supp_timer.function = wl_cfg80211_scan_supp_timerfunc; ++ INIT_WORK(&wl->wlan_work, wl_cfg80211_work_handler); ++#endif /* DHCP_SCAN_SUPPRESS */ ++ ++ wl_set_drv_status(wl, READY, ndev); ++ return err; ++} ++ ++static s32 __wl_cfg80211_down(struct wl_priv *wl) ++{ ++ s32 err = 0; ++ unsigned long flags; ++ struct net_info *iter, *next; ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ struct net_device *p2p_net = wl->p2p_net; ++ u32 bssidx = wl_cfgp2p_find_idx(wl, ndev); ++ AP6211_DEBUG("In\n"); ++ ++#if defined(DHCP_SCAN_SUPPRESS) ++ /* Force clear of scan_suppress */ ++ if (wl->scan_suppressed) ++ wl_cfg80211_scan_suppress(ndev, 0); ++ if (timer_pending(&wl->scan_supp_timer)) ++ del_timer_sync(&wl->scan_supp_timer); ++ cancel_work_sync(&wl->wlan_work); ++#endif /* DHCP_SCAN_SUPPRESS */ ++ ++ /* If BSS is operational (e.g SoftAp), bring it down */ ++ if (wl_cfgp2p_bss_isup(ndev, bssidx)) { ++ if (wl_cfgp2p_bss(wl, ndev, bssidx, 0) < 0) ++ AP6211_ERR("BSS down failed \n"); ++ } ++ ++ /* Check if cfg80211 interface is already down */ ++ if (!wl_get_drv_status(wl, READY, ndev)) ++ return err; /* it is even not ready */ ++ ++ for_each_ndev(wl, iter, next) ++ wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev); ++ ++ wl_term_iscan(wl); ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ if (wl->scan_request) { ++ cfg80211_scan_done(wl->scan_request, true); ++ wl->scan_request = NULL; ++ } ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ ++ for_each_ndev(wl, iter, next) { ++ wl_clr_drv_status(wl, READY, iter->ndev); ++ wl_clr_drv_status(wl, SCANNING, iter->ndev); ++ wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev); ++ wl_clr_drv_status(wl, CONNECTING, iter->ndev); ++ wl_clr_drv_status(wl, CONNECTED, iter->ndev); ++ wl_clr_drv_status(wl, DISCONNECTING, iter->ndev); ++ wl_clr_drv_status(wl, AP_CREATED, iter->ndev); ++ wl_clr_drv_status(wl, AP_CREATING, iter->ndev); ++ } ++ wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype = ++ NL80211_IFTYPE_STATION; ++ if (p2p_net) ++ dev_close(p2p_net); ++ DNGL_FUNC(dhd_cfg80211_down, (wl)); ++ wl_flush_eq(wl); ++ wl_link_down(wl); ++ if (wl->p2p_supported) ++ wl_cfgp2p_down(wl); ++ dhd_monitor_uninit(); ++ ++ return err; ++} ++ ++s32 wl_cfg80211_up(void *para) ++{ ++ struct wl_priv *wl; ++ s32 err = 0; ++ int val = 1; ++ dhd_pub_t *dhd; ++ ++ (void)para; ++ AP6211_DEBUG("In\n"); ++ wl = wlcfg_drv_priv; ++ ++ if ((err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_VERSION, &val, ++ sizeof(int), false) < 0)) { ++ AP6211_ERR("WLC_GET_VERSION failed, err=%d\n", err); ++ return err; ++ } ++ val = dtoh32(val); ++ if (val != WLC_IOCTL_VERSION && val != 1) { ++ AP6211_ERR("Version mismatch, please upgrade. Got %d, expected %d or 1\n", ++ val, WLC_IOCTL_VERSION); ++ return BCME_VERSION; ++ } ++ ioctl_version = val; ++ AP6211_DEBUG("WLC_GET_VERSION=%d\n", ioctl_version); ++ ++ mutex_lock(&wl->usr_sync); ++ dhd = (dhd_pub_t *)(wl->pub); ++ if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) { ++ err = wl_cfg80211_attach_post(wl_to_prmry_ndev(wl)); ++ if (unlikely(err)) ++ return err; ++ } ++ err = __wl_cfg80211_up(wl); ++ if (unlikely(err)) ++ AP6211_ERR("__wl_cfg80211_up failed\n"); ++ mutex_unlock(&wl->usr_sync); ++ return err; ++} ++ ++/* Private Event to Supplicant with indication that chip hangs */ ++int wl_cfg80211_hang(struct net_device *dev, u16 reason) ++{ ++ struct wl_priv *wl; ++ wl = wlcfg_drv_priv; ++ ++ AP6211_ERR("In : chip crash eventing\n"); ++ cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL); ++#if defined(RSSIAVG) ++ wl_free_rssi_cache(&g_rssi_cache_ctrl); ++#endif ++#if defined(BSSCACHE) ++ wl_free_bss_cache(&g_bss_cache_ctrl); ++ wl_run_bss_cache_timer(&g_bss_cache_ctrl, 0); ++#endif ++ if (wl != NULL) { ++ wl_link_down(wl); ++ } ++ return 0; ++} ++ ++s32 wl_cfg80211_down(void *para) ++{ ++ struct wl_priv *wl; ++ s32 err = 0; ++ ++ (void)para; ++ AP6211_DEBUG("In\n"); ++ wl = wlcfg_drv_priv; ++ mutex_lock(&wl->usr_sync); ++#if defined(RSSIAVG) ++ wl_free_rssi_cache(&g_rssi_cache_ctrl); ++#endif ++#if defined(BSSCACHE) ++ wl_free_bss_cache(&g_bss_cache_ctrl); ++ wl_run_bss_cache_timer(&g_bss_cache_ctrl, 0); ++#endif ++ err = __wl_cfg80211_down(wl); ++ mutex_unlock(&wl->usr_sync); ++ ++ return err; ++} ++ ++static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item) ++{ ++ unsigned long flags; ++ void *rptr = NULL; ++ struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); ++ ++ if (!profile) ++ return NULL; ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ switch (item) { ++ case WL_PROF_SEC: ++ rptr = &profile->sec; ++ break; ++ case WL_PROF_ACT: ++ rptr = &profile->active; ++ break; ++ case WL_PROF_BSSID: ++ rptr = profile->bssid; ++ break; ++ case WL_PROF_SSID: ++ rptr = &profile->ssid; ++ break; ++ case WL_PROF_CHAN: ++ rptr = &profile->channel; ++ break; ++ } ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ if (!rptr) ++ AP6211_ERR("invalid item (%d)\n", item); ++ return rptr; ++} ++ ++static s32 ++wl_update_prof(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data, s32 item) ++{ ++ s32 err = 0; ++ struct wlc_ssid *ssid; ++ unsigned long flags; ++ struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); ++ ++ if (!profile) ++ return WL_INVALID; ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ switch (item) { ++ case WL_PROF_SSID: ++ ssid = (wlc_ssid_t *) data; ++ memset(profile->ssid.SSID, 0, ++ sizeof(profile->ssid.SSID)); ++ memcpy(profile->ssid.SSID, ssid->SSID, ssid->SSID_len); ++ profile->ssid.SSID_len = ssid->SSID_len; ++ break; ++ case WL_PROF_BSSID: ++ if (data) ++ memcpy(profile->bssid, data, ETHER_ADDR_LEN); ++ else ++ memset(profile->bssid, 0, ETHER_ADDR_LEN); ++ break; ++ case WL_PROF_SEC: ++ memcpy(&profile->sec, data, sizeof(profile->sec)); ++ break; ++ case WL_PROF_ACT: ++ profile->active = *(bool *)data; ++ break; ++ case WL_PROF_BEACONINT: ++ profile->beacon_interval = *(u16 *)data; ++ break; ++ case WL_PROF_DTIMPERIOD: ++ profile->dtim_period = *(u8 *)data; ++ break; ++ case WL_PROF_CHAN: ++ profile->channel = *(u32*)data; ++ default: ++ err = -EOPNOTSUPP; ++ break; ++ } ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ ++ if (err == EOPNOTSUPP) ++ AP6211_ERR("unsupported item (%d)\n", item); ++ ++ return err; ++} ++ ++void wl_cfg80211_dbg_level(u32 level) ++{ ++ /* ++ * prohibit to change debug level ++ * by insmod parameter. ++ * eventually debug level will be configured ++ * in compile time by using CONFIG_XXX ++ */ ++ /* wl_dbg_level = level; */ ++} ++ ++static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev) ++{ ++ return wl_get_mode_by_netdev(wl, ndev) == WL_MODE_IBSS; ++} ++ ++static __used bool wl_is_ibssstarter(struct wl_priv *wl) ++{ ++ return wl->ibss_starter; ++} ++ ++static void wl_rst_ie(struct wl_priv *wl) ++{ ++ struct wl_ie *ie = wl_to_ie(wl); ++ ++ ie->offset = 0; ++} ++ ++static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v) ++{ ++ struct wl_ie *ie = wl_to_ie(wl); ++ s32 err = 0; ++ ++ if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) { ++ AP6211_ERR("ei crosses buffer boundary\n"); ++ return -ENOSPC; ++ } ++ ie->buf[ie->offset] = t; ++ ie->buf[ie->offset + 1] = l; ++ memcpy(&ie->buf[ie->offset + 2], v, l); ++ ie->offset += l + 2; ++ ++ return err; ++} ++ ++static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size) ++{ ++ struct wl_ie *ie = wl_to_ie(wl); ++ s32 err = 0; ++ ++ if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) { ++ AP6211_ERR("ei_stream crosses buffer boundary\n"); ++ return -ENOSPC; ++ } ++ memcpy(&ie->buf[ie->offset], ie_stream, ie_size); ++ ie->offset += ie_size; ++ ++ return err; ++} ++ ++static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size) ++{ ++ struct wl_ie *ie = wl_to_ie(wl); ++ s32 err = 0; ++ ++ if (unlikely(ie->offset > dst_size)) { ++ AP6211_ERR("dst_size is not enough\n"); ++ return -ENOSPC; ++ } ++ memcpy(dst, &ie->buf[0], ie->offset); ++ ++ return err; ++} ++ ++static u32 wl_get_ielen(struct wl_priv *wl) ++{ ++ struct wl_ie *ie = wl_to_ie(wl); ++ ++ return ie->offset; ++} ++ ++static void wl_link_up(struct wl_priv *wl) ++{ ++ wl->link_up = true; ++} ++ ++static void wl_link_down(struct wl_priv *wl) ++{ ++ struct wl_connect_info *conn_info = wl_to_conn(wl); ++ ++ AP6211_DEBUG("In\n"); ++ wl->link_up = false; ++ conn_info->req_ie_len = 0; ++ conn_info->resp_ie_len = 0; ++} ++ ++static unsigned long wl_lock_eq(struct wl_priv *wl) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&wl->eq_lock, flags); ++ return flags; ++} ++ ++static void wl_unlock_eq(struct wl_priv *wl, unsigned long flags) ++{ ++ spin_unlock_irqrestore(&wl->eq_lock, flags); ++} ++ ++static void wl_init_eq_lock(struct wl_priv *wl) ++{ ++ spin_lock_init(&wl->eq_lock); ++} ++ ++static void wl_delay(u32 ms) ++{ ++ if (in_atomic() || (ms < jiffies_to_msecs(1))) { ++ mdelay(ms); ++ } else { ++ msleep(ms); ++ } ++} ++ ++s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ struct ether_addr p2pif_addr; ++ struct ether_addr primary_mac; ++ if (!wl->p2p) ++ return -1; ++ if (!p2p_is_on(wl)) { ++ get_primary_mac(wl, &primary_mac); ++ wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr); ++ } else { ++ memcpy(p2pdev_addr->octet, ++ wl->p2p->dev_addr.octet, ETHER_ADDR_LEN); ++ } ++ ++ ++ return 0; ++} ++s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) ++{ ++ struct wl_priv *wl; ++ ++ wl = wlcfg_drv_priv; ++ ++ return wl_cfgp2p_set_p2p_noa(wl, net, buf, len); ++} ++ ++s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) ++{ ++ struct wl_priv *wl; ++ wl = wlcfg_drv_priv; ++ ++ return wl_cfgp2p_get_p2p_noa(wl, net, buf, len); ++} ++ ++s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) ++{ ++ struct wl_priv *wl; ++ wl = wlcfg_drv_priv; ++ ++ return wl_cfgp2p_set_p2p_ps(wl, net, buf, len); ++} ++ ++s32 wl_cfg80211_channel_to_freq(u32 channel) ++{ ++ int freq = 0; ++ ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) ++ freq = ieee80211_channel_to_frequency(channel); ++#else ++ { ++ u16 band = 0; ++ if (channel <= CH_MAX_2G_CHANNEL) ++ band = IEEE80211_BAND_2GHZ; ++ else ++ band = IEEE80211_BAND_5GHZ; ++ freq = ieee80211_channel_to_frequency(channel, band); ++ } ++#endif ++ return freq; ++} ++ ++s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, ++ enum wl_management_type type) ++{ ++ struct wl_priv *wl; ++ struct net_device *ndev = NULL; ++ struct ether_addr primary_mac; ++ s32 ret = 0; ++ s32 bssidx = 0; ++ s32 pktflag = 0; ++ wl = wlcfg_drv_priv; ++ ++ if (wl_get_drv_status(wl, AP_CREATING, net) || ++ wl_get_drv_status(wl, AP_CREATED, net)) { ++ ndev = net; ++ bssidx = 0; ++ } else if (wl->p2p) { ++ if (net == wl->p2p_net) { ++ net = wl_to_prmry_ndev(wl); ++ } ++ if (!wl->p2p->on) { ++ get_primary_mac(wl, &primary_mac); ++ wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, ++ &wl->p2p->int_addr); ++ /* In case of p2p_listen command, supplicant send remain_on_channel ++ * without turning on P2P ++ */ ++ ++ p2p_on(wl) = true; ++ ret = wl_cfgp2p_enable_discovery(wl, net, NULL, 0); ++ ++ if (unlikely(ret)) { ++ goto exit; ++ } ++ } ++ if (net != wl_to_prmry_ndev(wl)) { ++ if (wl_get_mode_by_netdev(wl, net) == WL_MODE_AP) { ++ ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); ++ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION); ++ } ++ } else { ++ ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); ++ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); ++ } ++ } ++ if (ndev != NULL) { ++ switch (type) { ++ case WL_BEACON: ++ pktflag = VNDR_IE_BEACON_FLAG; ++ break; ++ case WL_PROBE_RESP: ++ pktflag = VNDR_IE_PRBRSP_FLAG; ++ break; ++ case WL_ASSOC_RESP: ++ pktflag = VNDR_IE_ASSOCRSP_FLAG; ++ break; ++ } ++ if (pktflag) ++ ret = wl_cfgp2p_set_management_ie(wl, ndev, bssidx, pktflag, buf, len); ++ } ++exit: ++ return ret; ++} ++ ++static const struct rfkill_ops wl_rfkill_ops = { ++ .set_block = wl_rfkill_set ++}; ++ ++static int wl_rfkill_set(void *data, bool blocked) ++{ ++ struct wl_priv *wl = (struct wl_priv *)data; ++ ++ AP6211_DEBUG("Enter \n"); ++ AP6211_DEBUG("RF %s\n", blocked ? "blocked" : "unblocked"); ++ ++ if (!wl) ++ return -EINVAL; ++ ++ wl->rf_blocked = blocked; ++ ++ return 0; ++} ++ ++static int wl_setup_rfkill(struct wl_priv *wl, bool setup) ++{ ++ s32 err = 0; ++ ++ AP6211_DEBUG("Enter \n"); ++ if (!wl) ++ return -EINVAL; ++ if (setup) { ++ wl->rfkill = rfkill_alloc("brcmfmac-wifi", ++ wl_cfg80211_get_parent_dev(), ++ RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)wl); ++ ++ if (!wl->rfkill) { ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ err = rfkill_register(wl->rfkill); ++ ++ if (err) ++ rfkill_destroy(wl->rfkill); ++ } else { ++ if (!wl->rfkill) { ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ rfkill_unregister(wl->rfkill); ++ rfkill_destroy(wl->rfkill); ++ } ++ ++err_out: ++ return err; ++} ++ ++struct device *wl_cfg80211_get_parent_dev(void) ++{ ++ return cfg80211_parent_dev; ++} ++ ++void wl_cfg80211_set_parent_dev(void *dev) ++{ ++ cfg80211_parent_dev = dev; ++} ++ ++static void wl_cfg80211_clear_parent_dev(void) ++{ ++ cfg80211_parent_dev = NULL; ++} ++ ++static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac) ++{ ++ wldev_iovar_getbuf_bsscfg(wl_to_prmry_ndev(wl), "cur_etheraddr", NULL, ++ 0, wl->ioctl_buf, WLC_IOCTL_SMLEN, 0, &wl->ioctl_buf_sync); ++ memcpy(mac->octet, wl->ioctl_buf, ETHER_ADDR_LEN); ++} ++ ++int wl_cfg80211_do_driver_init(struct net_device *net) ++{ ++ struct wl_priv *wl = *(struct wl_priv **)netdev_priv(net); ++ ++ if (!wl || !wl->wdev) ++ return -EINVAL; ++ ++ if (dhd_do_driver_init(wl->wdev->netdev) < 0) ++ return -1; ++ ++ return 0; ++} ++ ++void wl_cfg80211_enable_trace(u32 level) ++{ ++ wl_dbg_level = level; ++ AP6211_DEBUG("%s: wl_dbg_level = 0x%x\n", __FUNCTION__, wl_dbg_level); ++} ++ ++#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \ ++ 2, 0)) ++static s32 ++wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, ++ struct net_device *dev, u64 cookie) ++{ ++ /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION ++ * is passed with CMD_FRAME. This callback is supposed to cancel ++ * the OFFCHANNEL Wait. Since we are already taking care of that ++ * with the tx_mgmt logic, do nothing here. ++ */ ++ ++ return 0; ++} ++#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL >= 3.2.0 */ ++ ++#ifdef WL11U ++bcm_tlv_t * ++wl_cfg80211_find_interworking_ie(u8 *parse, u32 len) ++{ ++ bcm_tlv_t *ie; ++ ++ while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_INTERWORKING_ID))) { ++ return (bcm_tlv_t *)ie; ++ } ++ return NULL; ++} ++ ++static s32 ++wl_cfg80211_add_iw_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag, ++ uint8 ie_id, uint8 *data, uint8 data_len) ++{ ++ s32 err = BCME_OK; ++ s32 buf_len; ++ s32 iecount; ++ ie_setbuf_t *ie_setbuf; ++ ++ if (ie_id != DOT11_MNG_INTERWORKING_ID) ++ return BCME_UNSUPPORTED; ++ ++ /* Validate the pktflag parameter */ ++ if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | ++ VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | ++ VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG| ++ VNDR_IE_CUSTOM_FLAG))) { ++ AP6211_ERR("cfg80211 Add IE: Invalid packet flag 0x%x\n", pktflag); ++ return -1; ++ } ++ ++ /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */ ++ pktflag = htod32(pktflag); ++ ++ buf_len = sizeof(ie_setbuf_t) + data_len - 1; ++ ie_setbuf = (ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL); ++ ++ if (!ie_setbuf) { ++ AP6211_ERR("Error allocating buffer for IE\n"); ++ return -ENOMEM; ++ } ++ ++ if (wl->iw_ie_len == data_len && !memcmp(wl->iw_ie, data, data_len)) { ++ AP6211_ERR("Previous IW IE is equals to current IE\n"); ++ return err; ++ } ++ ++ strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1); ++ ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; ++ ++ /* Buffer contains only 1 IE */ ++ iecount = htod32(1); ++ memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int)); ++ memcpy((void *)&ie_setbuf->ie_buffer.ie_list[0].pktflag, &pktflag, sizeof(uint32)); ++ ++ /* Now, add the IE to the buffer */ ++ ie_setbuf->ie_buffer.ie_list[0].ie_data.id = ie_id; ++ ++ /* if already set with previous values, delete it first */ ++ if (wl->iw_ie_len != 0) { ++ AP6211_DEBUG("Different IW_IE was already set. clear first\n"); ++ ++ ie_setbuf->ie_buffer.ie_list[0].ie_data.len = 0; ++ ++ err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ ++ if (err != BCME_OK) ++ return err; ++ } ++ ++ ie_setbuf->ie_buffer.ie_list[0].ie_data.len = data_len; ++ memcpy((uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], data, data_len); ++ ++ err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ ++ if (err == BCME_OK) { ++ memcpy(wl->iw_ie, data, data_len); ++ wl->iw_ie_len = data_len; ++ wl->wl11u = TRUE; ++ ++ err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 1, bssidx); ++ } ++ ++ kfree(ie_setbuf); ++ return err; ++} ++#endif /* WL11U */ ++ ++#ifdef WL_HOST_BAND_MGMT ++s32 ++wl_cfg80211_set_band(struct net_device *ndev, int band) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ int ret = 0; ++ char ioctl_buf[50]; ++ ++ if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) { ++ AP6211_ERR("Invalid band\n"); ++ return -EINVAL; ++ } ++ ++ if ((ret = wldev_iovar_setbuf(ndev, "roam_band", &band, ++ sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) { ++ AP6211_ERR("seting roam_band failed code=%d\n", ret); ++ return ret; ++ } ++ ++ AP6211_DEBUG("Setting band to %d\n", band); ++ wl->curr_band = band; ++ ++ return 0; ++} ++#endif /* WL_HOST_BAND_MGMT */ ++ ++#if defined(DHCP_SCAN_SUPPRESS) ++static void wl_cfg80211_scan_supp_timerfunc(ulong data) ++{ ++ struct wl_priv *wl = (struct wl_priv *)data; ++ ++ AP6211_DEBUG("Enter \n"); ++ schedule_work(&wl->wlan_work); ++} ++ ++static void wl_cfg80211_work_handler(struct work_struct *work) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ ++ wl = container_of(work, struct wl_priv, wlan_work); ++ ++ if (!wl) { ++ AP6211_ERR("wl_priv ptr NULL\n"); ++ return; ++ } ++ ++ if (wl->scan_suppressed) { ++ /* There is pending scan_suppress. Clean it */ ++ AP6211_ERR("Clean up from timer after %d msec\n", WL_SCAN_SUPPRESS_TIMEOUT); ++ wl_cfg80211_scan_suppress(wl_to_prmry_ndev(wl), 0); ++ } ++} ++ ++int wl_cfg80211_scan_suppress(struct net_device *dev, int suppress) ++{ ++ struct wl_priv *wl = wlcfg_drv_priv; ++ int ret = 0; ++ ++ if (!dev || !wl || ((suppress != 0) && (suppress != 1))) ++ return -EINVAL; ++ ++ if (suppress == wl->scan_suppressed) { ++ AP6211_DEBUG("No change in scan_suppress state. Ignoring cmd..\n"); ++ return 0; ++ } ++ ++ if (timer_pending(&wl->scan_supp_timer)) ++ del_timer_sync(&wl->scan_supp_timer); ++ ++ if ((ret = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS, ++ &suppress, sizeof(int), true)) < 0) { ++ AP6211_ERR("Scan suppress setting failed ret:%d \n", ret); ++ } else { ++ AP6211_DEBUG("Scan suppress %s \n", suppress ? "Enabled" : "Disabled"); ++ wl->scan_suppressed = suppress; ++ } ++ ++ /* If scan_suppress is set, Start a timer to monitor it (just incase) */ ++ if (wl->scan_suppressed) { ++ if (ret) { ++ AP6211_ERR("Retry scan_suppress reset at a later time \n"); ++ mod_timer(&wl->scan_supp_timer, ++ jiffies + msecs_to_jiffies(WL_SCAN_SUPPRESS_RETRY)); ++ } else { ++ AP6211_DEBUG("Start wlan_timer to clear of scan_suppress \n"); ++ mod_timer(&wl->scan_supp_timer, ++ jiffies + msecs_to_jiffies(WL_SCAN_SUPPRESS_TIMEOUT)); ++ } ++ } ++ ++ return ret; ++} ++#endif /* DHCP_SCAN_SUPPRESS */ +diff --git a/drivers/net/wireless/ap6211/wl_cfg80211.h b/drivers/net/wireless/ap6211/wl_cfg80211.h +new file mode 100755 +index 0000000..01dd136 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_cfg80211.h +@@ -0,0 +1,791 @@ ++/* ++ * Linux cfg80211 driver ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_cfg80211.h 374275 2012-12-12 11:44:18Z $ ++ */ ++ ++#ifndef _wl_cfg80211_h_ ++#define _wl_cfg80211_h_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++struct wl_conf; ++struct wl_iface; ++struct wl_priv; ++struct wl_security; ++struct wl_ibss; ++ ++ ++#define htod32(i) i ++#define htod16(i) i ++#define dtoh32(i) i ++#define dtoh16(i) i ++#define htodchanspec(i) i ++#define dtohchanspec(i) i ++ ++#define WL_DBG_NONE 0 ++#define WL_DBG_P2P_ACTION (1 << 5) ++#define WL_DBG_TRACE (1 << 4) ++#define WL_DBG_SCAN (1 << 3) ++#define WL_DBG_DBG (1 << 2) ++#define WL_DBG_INFO (1 << 1) ++#define WL_DBG_ERR (1 << 0) ++ ++/* 0 invalidates all debug messages. default is 1 */ ++#define WL_DBG_LEVEL 0xFF ++ ++#define WL_SCAN_RETRY_MAX 3 ++#define WL_NUM_PMKIDS_MAX MAXPMKID ++#define WL_SCAN_BUF_MAX (1024 * 8) ++#define WL_TLV_INFO_MAX 1500 ++#define WL_SCAN_IE_LEN_MAX 2048 ++#define WL_BSS_INFO_MAX 2048 ++#define WL_ASSOC_INFO_MAX 512 ++#define WL_IOCTL_LEN_MAX 1024 ++#define WL_EXTRA_BUF_MAX 2048 ++#define WL_ISCAN_BUF_MAX 2048 ++#define WL_ISCAN_TIMER_INTERVAL_MS 3000 ++#define WL_SCAN_ERSULTS_LAST (WL_SCAN_RESULTS_NO_MEM+1) ++#define WL_AP_MAX 256 ++#define WL_FILE_NAME_MAX 256 ++#define WL_DWELL_TIME 200 ++#define WL_MED_DWELL_TIME 400 ++#define WL_MIN_DWELL_TIME 100 ++#define WL_LONG_DWELL_TIME 1000 ++#define IFACE_MAX_CNT 2 ++#define WL_SCAN_CONNECT_DWELL_TIME_MS 200 ++#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20 ++#define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320 ++#define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400 ++#define WL_AF_TX_MAX_RETRY 5 ++ ++#define WL_SCAN_TIMER_INTERVAL_MS 8000 /* Scan timeout */ ++#define WL_CHANNEL_SYNC_RETRY 5 ++#define WL_INVALID -1 ++ ++/* Bring down SCB Timeout to 20secs from 60secs default */ ++#ifndef WL_SCB_TIMEOUT ++#define WL_SCB_TIMEOUT 20 ++#endif ++ ++/* SCAN_SUPPRESS timer values in ms */ ++#define WL_SCAN_SUPPRESS_TIMEOUT 31000 /* default Framwork DHCP timeout is 30 sec */ ++#define WL_SCAN_SUPPRESS_RETRY 3000 ++ ++/* driver status */ ++enum wl_status { ++ WL_STATUS_READY = 0, ++ WL_STATUS_SCANNING, ++ WL_STATUS_SCAN_ABORTING, ++ WL_STATUS_CONNECTING, ++ WL_STATUS_CONNECTED, ++ WL_STATUS_DISCONNECTING, ++ WL_STATUS_AP_CREATING, ++ WL_STATUS_AP_CREATED, ++ /* whole sending action frame procedure: ++ * includes a) 'finding common channel' for public action request frame ++ * and b) 'sending af via 'actframe' iovar' ++ */ ++ WL_STATUS_SENDING_ACT_FRM, ++ /* find a peer to go to a common channel before sending public action req frame */ ++ WL_STATUS_FINDING_COMMON_CHANNEL, ++ /* waiting for next af to sync time of supplicant. ++ * it includes SENDING_ACT_FRM and WAITING_NEXT_ACT_FRM_LISTEN ++ */ ++ WL_STATUS_WAITING_NEXT_ACT_FRM, ++#ifdef WL_CFG80211_SYNC_GON ++ /* go to listen state to wait for next af after SENDING_ACT_FRM */ ++ WL_STATUS_WAITING_NEXT_ACT_FRM_LISTEN, ++#endif /* WL_CFG80211_SYNC_GON */ ++ /* it will be set when upper layer requests listen and succeed in setting listen mode. ++ * if set, other scan request can abort current listen state ++ */ ++ WL_STATUS_REMAINING_ON_CHANNEL, ++#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ /* it's fake listen state to keep current scan state. ++ * it will be set when upper layer requests listen but scan is running. then just run ++ * a expire timer without actual listen state. ++ * if set, other scan request does not need to abort scan. ++ */ ++ WL_STATUS_FAKE_REMAINING_ON_CHANNEL ++#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++}; ++ ++/* wi-fi mode */ ++enum wl_mode { ++ WL_MODE_BSS, ++ WL_MODE_IBSS, ++ WL_MODE_AP ++}; ++ ++/* driver profile list */ ++enum wl_prof_list { ++ WL_PROF_MODE, ++ WL_PROF_SSID, ++ WL_PROF_SEC, ++ WL_PROF_IBSS, ++ WL_PROF_BAND, ++ WL_PROF_CHAN, ++ WL_PROF_BSSID, ++ WL_PROF_ACT, ++ WL_PROF_BEACONINT, ++ WL_PROF_DTIMPERIOD ++}; ++ ++/* driver iscan state */ ++enum wl_iscan_state { ++ WL_ISCAN_STATE_IDLE, ++ WL_ISCAN_STATE_SCANING ++}; ++ ++/* donlge escan state */ ++enum wl_escan_state { ++ WL_ESCAN_STATE_IDLE, ++ WL_ESCAN_STATE_SCANING ++}; ++/* fw downloading status */ ++enum wl_fw_status { ++ WL_FW_LOADING_DONE, ++ WL_NVRAM_LOADING_DONE ++}; ++ ++enum wl_management_type { ++ WL_BEACON = 0x1, ++ WL_PROBE_RESP = 0x2, ++ WL_ASSOC_RESP = 0x4 ++}; ++/* beacon / probe_response */ ++struct beacon_proberesp { ++ __le64 timestamp; ++ __le16 beacon_int; ++ __le16 capab_info; ++ u8 variable[0]; ++} __attribute__ ((packed)); ++ ++/* driver configuration */ ++struct wl_conf { ++ u32 frag_threshold; ++ u32 rts_threshold; ++ u32 retry_short; ++ u32 retry_long; ++ s32 tx_power; ++ struct ieee80211_channel channel; ++}; ++ ++typedef s32(*EVENT_HANDLER) (struct wl_priv *wl, ++ struct net_device *ndev, const wl_event_msg_t *e, void *data); ++ ++/* bss inform structure for cfg80211 interface */ ++struct wl_cfg80211_bss_info { ++ u16 band; ++ u16 channel; ++ s16 rssi; ++ u16 frame_len; ++ u8 frame_buf[1]; ++}; ++ ++/* basic structure of scan request */ ++struct wl_scan_req { ++ struct wlc_ssid ssid; ++}; ++ ++/* basic structure of information element */ ++struct wl_ie { ++ u16 offset; ++ u8 buf[WL_TLV_INFO_MAX]; ++}; ++ ++/* event queue for cfg80211 main event */ ++struct wl_event_q { ++ struct list_head eq_list; ++ u32 etype; ++ wl_event_msg_t emsg; ++ s8 edata[1]; ++}; ++ ++/* security information with currently associated ap */ ++struct wl_security { ++ u32 wpa_versions; ++ u32 auth_type; ++ u32 cipher_pairwise; ++ u32 cipher_group; ++ u32 wpa_auth; ++ u32 auth_assoc_res_status; ++}; ++ ++/* ibss information for currently joined ibss network */ ++struct wl_ibss { ++ u8 beacon_interval; /* in millisecond */ ++ u8 atim; /* in millisecond */ ++ s8 join_only; ++ u8 band; ++ u8 channel; ++}; ++ ++/* wl driver profile */ ++struct wl_profile { ++ u32 mode; ++ s32 band; ++ u32 channel; ++ struct wlc_ssid ssid; ++ struct wl_security sec; ++ struct wl_ibss ibss; ++ u8 bssid[ETHER_ADDR_LEN]; ++ u16 beacon_interval; ++ u8 dtim_period; ++ bool active; ++}; ++ ++struct net_info { ++ struct net_device *ndev; ++ struct wireless_dev *wdev; ++ struct wl_profile profile; ++ s32 mode; ++ s32 roam_off; ++ unsigned long sme_state; ++ bool pm_restore; ++ bool pm_block; ++ s32 pm; ++ struct list_head list; /* list of all net_info structure */ ++}; ++typedef s32(*ISCAN_HANDLER) (struct wl_priv *wl); ++ ++/* iscan controller */ ++struct wl_iscan_ctrl { ++ struct net_device *dev; ++ struct timer_list timer; ++ u32 timer_ms; ++ u32 timer_on; ++ s32 state; ++ struct task_struct *tsk; ++ struct semaphore sync; ++ ISCAN_HANDLER iscan_handler[WL_SCAN_ERSULTS_LAST]; ++ void *data; ++ s8 ioctl_buf[WLC_IOCTL_SMLEN]; ++ s8 scan_buf[WL_ISCAN_BUF_MAX]; ++}; ++ ++/* association inform */ ++#define MAX_REQ_LINE 1024 ++struct wl_connect_info { ++ u8 req_ie[MAX_REQ_LINE]; ++ s32 req_ie_len; ++ u8 resp_ie[MAX_REQ_LINE]; ++ s32 resp_ie_len; ++}; ++ ++/* firmware /nvram downloading controller */ ++struct wl_fw_ctrl { ++ const struct firmware *fw_entry; ++ unsigned long status; ++ u32 ptr; ++ s8 fw_name[WL_FILE_NAME_MAX]; ++ s8 nvram_name[WL_FILE_NAME_MAX]; ++}; ++ ++/* assoc ie length */ ++struct wl_assoc_ielen { ++ u32 req_len; ++ u32 resp_len; ++}; ++ ++/* wpa2 pmk list */ ++struct wl_pmk_list { ++ pmkid_list_t pmkids; ++ pmkid_t foo[MAXPMKID - 1]; ++}; ++ ++ ++#define ESCAN_BUF_SIZE (64 * 1024) ++ ++struct escan_info { ++ u32 escan_state; ++#if defined(STATIC_WL_PRIV_STRUCT) ++#ifndef CONFIG_DHD_USE_STATIC_BUF ++#error STATIC_WL_PRIV_STRUCT should be used with CONFIG_DHD_USE_STATIC_BUF ++#endif ++ u8 *escan_buf; ++#else ++ u8 escan_buf[ESCAN_BUF_SIZE]; ++#endif /* STATIC_WL_PRIV_STRUCT */ ++ struct wiphy *wiphy; ++ struct net_device *ndev; ++}; ++ ++struct ap_info { ++/* Structure to hold WPS, WPA IEs for a AP */ ++ u8 probe_res_ie[VNDR_IES_MAX_BUF_LEN]; ++ u8 beacon_ie[VNDR_IES_MAX_BUF_LEN]; ++ u32 probe_res_ie_len; ++ u32 beacon_ie_len; ++ u8 *wpa_ie; ++ u8 *rsn_ie; ++ u8 *wps_ie; ++ bool security_mode; ++}; ++struct btcoex_info { ++ struct timer_list timer; ++ u32 timer_ms; ++ u32 timer_on; ++ u32 ts_dhcp_start; /* ms ts ecord time stats */ ++ u32 ts_dhcp_ok; /* ms ts ecord time stats */ ++ bool dhcp_done; /* flag, indicates that host done with ++ * dhcp before t1/t2 expiration ++ */ ++ s32 bt_state; ++ struct work_struct work; ++ struct net_device *dev; ++}; ++ ++struct sta_info { ++ /* Structure to hold WPS IE for a STA */ ++ u8 probe_req_ie[VNDR_IES_BUF_LEN]; ++ u8 assoc_req_ie[VNDR_IES_BUF_LEN]; ++ u32 probe_req_ie_len; ++ u32 assoc_req_ie_len; ++}; ++ ++struct afx_hdl { ++ wl_af_params_t *pending_tx_act_frm; ++ struct ether_addr tx_dst_addr; ++ struct net_device *dev; ++ struct work_struct work; ++ u32 bssidx; ++ u32 retry; ++ s32 peer_chan; ++ s32 peer_listen_chan; /* search channel: configured by upper layer */ ++ s32 my_listen_chan; /* listen chanel: extract it from prb req or gon req */ ++ bool is_listen; ++ bool ack_recv; ++ bool is_active; ++}; ++ ++struct parsed_ies { ++ wpa_ie_fixed_t *wps_ie; ++ u32 wps_ie_len; ++ wpa_ie_fixed_t *wpa_ie; ++ u32 wpa_ie_len; ++ bcm_tlv_t *wpa2_ie; ++ u32 wpa2_ie_len; ++}; ++ ++ ++#ifdef WL11U ++/* Max length of Interworking element */ ++#define IW_IES_MAX_BUF_LEN 9 ++#endif ++ ++#define MAX_EVENT_BUF_NUM 16 ++typedef struct wl_eventmsg_buf { ++ u16 num; ++ struct { ++ u16 type; ++ bool set; ++ } event [MAX_EVENT_BUF_NUM]; ++} wl_eventmsg_buf_t; ++ ++/* private data of cfg80211 interface */ ++struct wl_priv { ++ struct wireless_dev *wdev; /* representing wl cfg80211 device */ ++ ++ struct wireless_dev *p2p_wdev; /* representing wl cfg80211 device for P2P */ ++ struct net_device *p2p_net; /* reference to p2p0 interface */ ++ ++ struct wl_conf *conf; ++ struct cfg80211_scan_request *scan_request; /* scan request object */ ++ EVENT_HANDLER evt_handler[WLC_E_LAST]; ++ struct list_head eq_list; /* used for event queue */ ++ struct list_head net_list; /* used for struct net_info */ ++ spinlock_t eq_lock; /* for event queue synchronization */ ++ spinlock_t cfgdrv_lock; /* to protect scan status (and others if needed) */ ++ struct completion act_frm_scan; ++ struct completion iface_disable; ++ struct completion wait_next_af; ++ struct mutex usr_sync; /* maily for up/down synchronization */ ++ struct wl_scan_results *bss_list; ++ struct wl_scan_results *scan_results; ++ ++ /* scan request object for internal purpose */ ++ struct wl_scan_req *scan_req_int; ++ /* information element object for internal purpose */ ++#if defined(STATIC_WL_PRIV_STRUCT) ++ struct wl_ie *ie; ++#else ++ struct wl_ie ie; ++#endif ++ struct wl_iscan_ctrl *iscan; /* iscan controller */ ++ ++ /* association information container */ ++#if defined(STATIC_WL_PRIV_STRUCT) ++ struct wl_connect_info *conn_info; ++#else ++ struct wl_connect_info conn_info; ++#endif ++ ++ struct wl_pmk_list *pmk_list; /* wpa2 pmk list */ ++ tsk_ctl_t event_tsk; /* task of main event handler thread */ ++ void *pub; ++ u32 iface_cnt; ++ u32 channel; /* current channel */ ++ u32 af_sent_channel; /* channel action frame is sent */ ++ /* next af subtype to cancel the remained dwell time in rx process */ ++ u8 next_af_subtype; ++#ifdef WL_CFG80211_SYNC_GON ++ ulong af_tx_sent_jiffies; ++#endif /* WL_CFG80211_SYNC_GON */ ++ bool iscan_on; /* iscan on/off switch */ ++ bool iscan_kickstart; /* indicate iscan already started */ ++ bool escan_on; /* escan on/off switch */ ++ struct escan_info escan_info; /* escan information */ ++ bool active_scan; /* current scan mode */ ++ bool ibss_starter; /* indicates this sta is ibss starter */ ++ bool link_up; /* link/connection up flag */ ++ ++ /* indicate whether chip to support power save mode */ ++ bool pwr_save; ++ bool roam_on; /* on/off switch for self-roaming */ ++ bool scan_tried; /* indicates if first scan attempted */ ++ bool wlfc_on; ++ bool vsdb_mode; ++ bool roamoff_on_concurrent; ++ u8 *ioctl_buf; /* ioctl buffer */ ++ struct mutex ioctl_buf_sync; ++ u8 *escan_ioctl_buf; ++ u8 *extra_buf; /* maily to grab assoc information */ ++ struct dentry *debugfsdir; ++ struct rfkill *rfkill; ++ bool rf_blocked; ++ struct ieee80211_channel remain_on_chan; ++ enum nl80211_channel_type remain_on_chan_type; ++ u64 send_action_id; ++ u64 last_roc_id; ++ wait_queue_head_t netif_change_event; ++ struct completion send_af_done; ++ struct afx_hdl *afx_hdl; ++ struct ap_info *ap_info; ++ struct sta_info *sta_info; ++ struct p2p_info *p2p; ++ bool p2p_supported; ++ struct btcoex_info *btcoex_info; ++ struct timer_list scan_timeout; /* Timer for catch scan event timeout */ ++ s32(*state_notifier) (struct wl_priv *wl, ++ struct net_info *_net_info, enum wl_status state, bool set); ++ unsigned long interrested_state; ++ wlc_ssid_t hostapd_ssid; ++#ifdef WL11U ++ bool wl11u; ++ u8 iw_ie[IW_IES_MAX_BUF_LEN]; ++ u32 iw_ie_len; ++#endif /* WL11U */ ++ bool sched_scan_running; /* scheduled scan req status */ ++#ifdef WL_SCHED_SCAN ++ struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */ ++#endif /* WL_SCHED_SCAN */ ++#ifdef WL_HOST_BAND_MGMT ++ u8 curr_band; ++#endif /* WL_HOST_BAND_MGMT */ ++ bool scan_suppressed; ++ struct timer_list scan_supp_timer; ++ struct work_struct wlan_work; ++ struct mutex event_sync; /* maily for up/down synchronization */ ++}; ++ ++ ++static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss) ++{ ++ return bss = bss ? ++ (struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info; ++} ++static inline s32 ++wl_alloc_netinfo(struct wl_priv *wl, struct net_device *ndev, ++ struct wireless_dev * wdev, s32 mode, bool pm_block) ++{ ++ struct net_info *_net_info; ++ s32 err = 0; ++ if (wl->iface_cnt == IFACE_MAX_CNT) ++ return -ENOMEM; ++ _net_info = kzalloc(sizeof(struct net_info), GFP_KERNEL); ++ if (!_net_info) ++ err = -ENOMEM; ++ else { ++ _net_info->mode = mode; ++ _net_info->ndev = ndev; ++ _net_info->wdev = wdev; ++ _net_info->pm_restore = 0; ++ _net_info->pm = 0; ++ _net_info->pm_block = pm_block; ++ _net_info->roam_off = WL_INVALID; ++ wl->iface_cnt++; ++ list_add(&_net_info->list, &wl->net_list); ++ } ++ return err; ++} ++static inline void ++wl_dealloc_netinfo(struct wl_priv *wl, struct net_device *ndev) ++{ ++ struct net_info *_net_info, *next; ++ ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ if (ndev && (_net_info->ndev == ndev)) { ++ list_del(&_net_info->list); ++ wl->iface_cnt--; ++ if (_net_info->wdev) { ++ kfree(_net_info->wdev); ++ ndev->ieee80211_ptr = NULL; ++ } ++ kfree(_net_info); ++ } ++ } ++ ++} ++static inline void ++wl_delete_all_netinfo(struct wl_priv *wl) ++{ ++ struct net_info *_net_info, *next; ++ ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ list_del(&_net_info->list); ++ if (_net_info->wdev) ++ kfree(_net_info->wdev); ++ kfree(_net_info); ++ } ++ wl->iface_cnt = 0; ++} ++static inline u32 ++wl_get_status_all(struct wl_priv *wl, s32 status) ++ ++{ ++ struct net_info *_net_info, *next; ++ u32 cnt = 0; ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ if (_net_info->ndev && ++ test_bit(status, &_net_info->sme_state)) ++ cnt++; ++ } ++ return cnt; ++} ++static inline void ++wl_set_status_all(struct wl_priv *wl, s32 status, u32 op) ++{ ++ struct net_info *_net_info, *next; ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ switch (op) { ++ case 1: ++ return; /* set all status is not allowed */ ++ case 2: ++ clear_bit(status, &_net_info->sme_state); ++ if (wl->state_notifier && ++ test_bit(status, &(wl->interrested_state))) ++ wl->state_notifier(wl, _net_info, status, false); ++ break; ++ case 4: ++ return; /* change all status is not allowed */ ++ default: ++ return; /* unknown operation */ ++ } ++ } ++} ++static inline void ++wl_set_status_by_netdev(struct wl_priv *wl, s32 status, ++ struct net_device *ndev, u32 op) ++{ ++ ++ struct net_info *_net_info, *next; ++ ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ if (ndev && (_net_info->ndev == ndev)) { ++ switch (op) { ++ case 1: ++ set_bit(status, &_net_info->sme_state); ++ if (wl->state_notifier && ++ test_bit(status, &(wl->interrested_state))) ++ wl->state_notifier(wl, _net_info, status, true); ++ break; ++ case 2: ++ clear_bit(status, &_net_info->sme_state); ++ if (wl->state_notifier && ++ test_bit(status, &(wl->interrested_state))) ++ wl->state_notifier(wl, _net_info, status, false); ++ break; ++ case 4: ++ change_bit(status, &_net_info->sme_state); ++ break; ++ } ++ } ++ ++ } ++ ++} ++ ++static inline u32 ++wl_get_status_by_netdev(struct wl_priv *wl, s32 status, ++ struct net_device *ndev) ++{ ++ struct net_info *_net_info, *next; ++ ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ if (ndev && (_net_info->ndev == ndev)) ++ return test_bit(status, &_net_info->sme_state); ++ } ++ return 0; ++} ++ ++static inline s32 ++wl_get_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev) ++{ ++ struct net_info *_net_info, *next; ++ ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ if (ndev && (_net_info->ndev == ndev)) ++ return _net_info->mode; ++ } ++ return -1; ++} ++ ++ ++static inline void ++wl_set_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev, ++ s32 mode) ++{ ++ struct net_info *_net_info, *next; ++ ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ if (ndev && (_net_info->ndev == ndev)) ++ _net_info->mode = mode; ++ } ++} ++static inline struct wl_profile * ++wl_get_profile_by_netdev(struct wl_priv *wl, struct net_device *ndev) ++{ ++ struct net_info *_net_info, *next; ++ ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ if (ndev && (_net_info->ndev == ndev)) ++ return &_net_info->profile; ++ } ++ return NULL; ++} ++static inline struct net_info * ++wl_get_netinfo_by_netdev(struct wl_priv *wl, struct net_device *ndev) ++{ ++ struct net_info *_net_info, *next; ++ ++ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { ++ if (ndev && (_net_info->ndev == ndev)) ++ return _net_info; ++ } ++ return NULL; ++} ++#define wl_to_wiphy(w) (w->wdev->wiphy) ++#define wl_to_prmry_ndev(w) (w->wdev->netdev) ++#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr)) ++#define wl_to_sr(w) (w->scan_req_int) ++#if defined(STATIC_WL_PRIV_STRUCT) ++#define wl_to_ie(w) (w->ie) ++#define wl_to_conn(w) (w->conn_info) ++#else ++#define wl_to_ie(w) (&w->ie) ++#define wl_to_conn(w) (&w->conn_info) ++#endif ++#define iscan_to_wl(i) ((struct wl_priv *)(i->data)) ++#define wl_to_iscan(w) (w->iscan) ++#define wiphy_from_scan(w) (w->escan_info.wiphy) ++#define wl_get_drv_status_all(wl, stat) \ ++ (wl_get_status_all(wl, WL_STATUS_ ## stat)) ++#define wl_get_drv_status(wl, stat, ndev) \ ++ (wl_get_status_by_netdev(wl, WL_STATUS_ ## stat, ndev)) ++#define wl_set_drv_status(wl, stat, ndev) \ ++ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 1)) ++#define wl_clr_drv_status(wl, stat, ndev) \ ++ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 2)) ++#define wl_clr_drv_status_all(wl, stat) \ ++ (wl_set_status_all(wl, WL_STATUS_ ## stat, 2)) ++#define wl_chg_drv_status(wl, stat, ndev) \ ++ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 4)) ++ ++#define for_each_bss(list, bss, __i) \ ++ for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss)) ++ ++#define for_each_ndev(wl, iter, next) \ ++ list_for_each_entry_safe(iter, next, &wl->net_list, list) ++ ++ ++/* In case of WPS from wpa_supplicant, pairwise siute and group suite is 0. ++ * In addtion to that, wpa_version is WPA_VERSION_1 ++ */ ++#define is_wps_conn(_sme) \ ++ ((wl_cfgp2p_find_wpsie((u8 *)_sme->ie, _sme->ie_len) != NULL) && \ ++ (!_sme->crypto.n_ciphers_pairwise) && \ ++ (!_sme->crypto.cipher_group)) ++extern s32 wl_cfg80211_attach(struct net_device *ndev, void *data); ++extern s32 wl_cfg80211_attach_post(struct net_device *ndev); ++extern void wl_cfg80211_detach(void *para); ++ ++extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e, ++ void *data); ++void wl_cfg80211_set_parent_dev(void *dev); ++struct device *wl_cfg80211_get_parent_dev(void); ++ ++extern s32 wl_cfg80211_up(void *para); ++extern s32 wl_cfg80211_down(void *para); ++extern s32 wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx, ++ void* _net_attach); ++extern s32 wl_cfg80211_ifdel_ops(struct net_device *net); ++extern s32 wl_cfg80211_notify_ifdel(void); ++extern s32 wl_cfg80211_is_progress_ifadd(void); ++extern s32 wl_cfg80211_is_progress_ifchange(void); ++extern s32 wl_cfg80211_is_progress_ifadd(void); ++extern s32 wl_cfg80211_notify_ifchange(void); ++extern void wl_cfg80211_dbg_level(u32 level); ++extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); ++extern s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len); ++extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len); ++extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, ++ enum wl_management_type type); ++extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len); ++extern int wl_cfg80211_hang(struct net_device *dev, u16 reason); ++extern s32 wl_mode_to_nl80211_iftype(s32 mode); ++int wl_cfg80211_do_driver_init(struct net_device *net); ++void wl_cfg80211_enable_trace(u32 level); ++extern s32 wl_update_wiphybands(struct wl_priv *wl, bool notify); ++extern s32 wl_cfg80211_if_is_group_owner(void); ++extern chanspec_t wl_ch_host_to_driver(u16 channel); ++extern s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add); ++extern void wl_stop_wait_next_action_frame(struct wl_priv *wl, struct net_device *ndev); ++extern s32 wl_cfg80211_set_band(struct net_device *ndev, int band); ++extern int wl_cfg80211_update_power_mode(struct net_device *dev); ++#if defined(DHCP_SCAN_SUPPRESS) ++extern int wl_cfg80211_scan_suppress(struct net_device *dev, int suppress); ++#endif /* OEM_ANDROID */ ++extern void wl_cfg80211_add_to_eventbuffer(wl_eventmsg_buf_t *ev, u16 event, bool set); ++extern s32 wl_cfg80211_apply_eventbuffer(struct net_device *ndev, ++ struct wl_priv *wl, wl_eventmsg_buf_t *ev); ++#endif /* _wl_cfg80211_h_ */ +diff --git a/drivers/net/wireless/ap6211/wl_cfgp2p.c b/drivers/net/wireless/ap6211/wl_cfgp2p.c +new file mode 100755 +index 0000000..eb7df08 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_cfgp2p.c +@@ -0,0 +1,2393 @@ ++/* ++ * Linux cfgp2p driver ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_cfgp2p.c 372668 2012-12-04 14:07:12Z $ ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++static s8 scanparambuf[WLC_IOCTL_SMLEN]; ++static s8 g_mgmt_ie_buf[2048]; ++static bool ++wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type); ++ ++static u32 ++wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 bssidx, s32 pktflag, ++ s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd); ++ ++static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev); ++static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd); ++static int wl_cfgp2p_if_open(struct net_device *net); ++static int wl_cfgp2p_if_stop(struct net_device *net); ++static s32 wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev, ++ bool notify); ++ ++static const struct net_device_ops wl_cfgp2p_if_ops = { ++ .ndo_open = wl_cfgp2p_if_open, ++ .ndo_stop = wl_cfgp2p_if_stop, ++ .ndo_do_ioctl = wl_cfgp2p_do_ioctl, ++ .ndo_start_xmit = wl_cfgp2p_start_xmit, ++}; ++ ++bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len) ++{ ++ wifi_p2p_pub_act_frame_t *pact_frm; ++ ++ if (frame == NULL) ++ return false; ++ pact_frm = (wifi_p2p_pub_act_frame_t *)frame; ++ if (frame_len < sizeof(wifi_p2p_pub_act_frame_t) -1) ++ return false; ++ ++ if (pact_frm->category == P2P_PUB_AF_CATEGORY && ++ pact_frm->action == P2P_PUB_AF_ACTION && ++ pact_frm->oui_type == P2P_VER && ++ memcmp(pact_frm->oui, P2P_OUI, sizeof(pact_frm->oui)) == 0) { ++ return true; ++ } ++ ++ return false; ++} ++ ++bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len) ++{ ++ wifi_p2p_action_frame_t *act_frm; ++ ++ if (frame == NULL) ++ return false; ++ act_frm = (wifi_p2p_action_frame_t *)frame; ++ if (frame_len < sizeof(wifi_p2p_action_frame_t) -1) ++ return false; ++ ++ if (act_frm->category == P2P_AF_CATEGORY && ++ act_frm->type == P2P_VER && ++ memcmp(act_frm->OUI, P2P_OUI, DOT11_OUI_LEN) == 0) { ++ return true; ++ } ++ ++ return false; ++} ++ ++/* ++* Currently Action frame just pass to P2P interface regardless real dst. ++* but GAS Action can be used for Hotspot2.0 as well ++* Need to distingush that it's for P2P or HS20 ++*/ ++#ifdef WL11U ++#define GAS_RESP_LEN 2 ++#define DOUBLE_TLV_BODY_OFF 4 ++#define GAS_RESP_OFFSET 4 ++#define GAS_CRESP_OFFSET 5 ++ ++bool wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len) ++{ ++ bcm_tlv_t *ie = (bcm_tlv_t *)data; ++ u8 *frame = NULL; ++ u16 id, flen; ++ ++ /* Skipped first ANQP Element, if frame has anqp elemnt */ ++ ie = bcm_parse_tlvs(ie, (int)len, DOT11_MNG_ADVERTISEMENT_ID); ++ ++ if (ie == NULL) ++ return false; ++ ++ frame = (uint8 *)ie + ie->len + TLV_HDR_LEN + GAS_RESP_LEN; ++ id = ((u16) (((frame)[1] << 8) | (frame)[0])); ++ flen = ((u16) (((frame)[3] << 8) | (frame)[2])); ++ ++ /* If the contents match the OUI and the type */ ++ if (flen >= WFA_OUI_LEN + 1 && ++ id == P2PSD_GAS_NQP_INFOID && ++ !bcmp(&frame[DOUBLE_TLV_BODY_OFF], (const uint8*)WFA_OUI, WFA_OUI_LEN) && ++ subtype == frame[DOUBLE_TLV_BODY_OFF+WFA_OUI_LEN]) { ++ return true; ++ } ++ ++ return false; ++} ++#endif /* WL11U */ ++ ++bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) ++{ ++ ++ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; ++ ++ if (frame == NULL) ++ return false; ++ ++ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; ++ if (frame_len < sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1) ++ return false; ++ if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) ++ return false; ++ ++#ifdef WL11U ++ if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP) ++ return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE, ++ (u8 *)sd_act_frm->query_data + GAS_RESP_OFFSET, ++ frame_len); ++ ++ else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) ++ return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE, ++ (u8 *)sd_act_frm->query_data + GAS_CRESP_OFFSET, ++ frame_len); ++ else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || ++ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ) ++ return true; ++ else ++ return false; ++#else ++ if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || ++ sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || ++ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || ++ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) ++ return true; ++ else ++ return false; ++#endif /* WLC11U */ ++} ++void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len) ++{ ++ wifi_p2p_pub_act_frame_t *pact_frm; ++ wifi_p2p_action_frame_t *act_frm; ++ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; ++ if (!frame || frame_len <= 2) ++ return; ++ ++ if (wl_cfgp2p_is_pub_action(frame, frame_len)) { ++ pact_frm = (wifi_p2p_pub_act_frame_t *)frame; ++ switch (pact_frm->subtype) { ++ case P2P_PAF_GON_REQ: ++ AP6211_DEBUG("%s P2P Group Owner Negotiation Req Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_PAF_GON_RSP: ++ AP6211_DEBUG("%s P2P Group Owner Negotiation Rsp Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_PAF_GON_CONF: ++ AP6211_DEBUG("%s P2P Group Owner Negotiation Confirm Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_PAF_INVITE_REQ: ++ AP6211_DEBUG("%s P2P Invitation Request Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_PAF_INVITE_RSP: ++ AP6211_DEBUG("%s P2P Invitation Response Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_PAF_DEVDIS_REQ: ++ AP6211_DEBUG("%s P2P Device Discoverability Request Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_PAF_DEVDIS_RSP: ++ AP6211_DEBUG("%s P2P Device Discoverability Response Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_PAF_PROVDIS_REQ: ++ AP6211_DEBUG("%s P2P Provision Discovery Request Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_PAF_PROVDIS_RSP: ++ AP6211_DEBUG("%s P2P Provision Discovery Response Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ default: ++ AP6211_DEBUG("%s Unknown P2P Public Action Frame\n", ++ (tx)? "TX": "RX"); ++ ++ } ++ ++ } else if (wl_cfgp2p_is_p2p_action(frame, frame_len)) { ++ act_frm = (wifi_p2p_action_frame_t *)frame; ++ switch (act_frm->subtype) { ++ case P2P_AF_NOTICE_OF_ABSENCE: ++ AP6211_DEBUG("%s P2P Notice of Absence Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_AF_PRESENCE_REQ: ++ AP6211_DEBUG("%s P2P Presence Request Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_AF_PRESENCE_RSP: ++ AP6211_DEBUG("%s P2P Presence Response Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ case P2P_AF_GO_DISC_REQ: ++ AP6211_DEBUG("%s P2P Discoverability Request Frame\n", ++ (tx)? "TX": "RX"); ++ break; ++ default: ++ AP6211_DEBUG("%s Unknown P2P Action Frame\n", ++ (tx)? "TX": "RX"); ++ } ++ ++ } else if (wl_cfgp2p_is_gas_action(frame, frame_len)) { ++ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; ++ switch (sd_act_frm->action) { ++ case P2PSD_ACTION_ID_GAS_IREQ: ++ AP6211_DEBUG("%s P2P GAS Initial Request\n", ++ (tx)? "TX" : "RX"); ++ break; ++ case P2PSD_ACTION_ID_GAS_IRESP: ++ AP6211_DEBUG("%s P2P GAS Initial Response\n", ++ (tx)? "TX" : "RX"); ++ break; ++ case P2PSD_ACTION_ID_GAS_CREQ: ++ AP6211_DEBUG("%s P2P GAS Comback Request\n", ++ (tx)? "TX" : "RX"); ++ break; ++ case P2PSD_ACTION_ID_GAS_CRESP: ++ AP6211_DEBUG("%s P2P GAS Comback Response\n", ++ (tx)? "TX" : "RX"); ++ break; ++ default: ++ AP6211_DEBUG("%s Unknown P2P GAS Frame\n", ++ (tx)? "TX" : "RX"); ++ } ++ ++ ++ } ++} ++ ++/* ++ * Initialize variables related to P2P ++ * ++ */ ++s32 ++wl_cfgp2p_init_priv(struct wl_priv *wl) ++{ ++ if (!(wl->p2p = kzalloc(sizeof(struct p2p_info), GFP_KERNEL))) { ++ AP6211_ERR("struct p2p_info allocation failed\n"); ++ return -ENOMEM; ++ } ++#define INIT_IE(IE_TYPE, BSS_TYPE) \ ++ do { \ ++ memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ ++ sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \ ++ wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \ ++ } while (0); ++ ++ INIT_IE(probe_req, P2PAPI_BSSCFG_PRIMARY); ++ INIT_IE(probe_res, P2PAPI_BSSCFG_PRIMARY); ++ INIT_IE(assoc_req, P2PAPI_BSSCFG_PRIMARY); ++ INIT_IE(assoc_res, P2PAPI_BSSCFG_PRIMARY); ++ INIT_IE(beacon, P2PAPI_BSSCFG_PRIMARY); ++ INIT_IE(probe_req, P2PAPI_BSSCFG_DEVICE); ++ INIT_IE(probe_res, P2PAPI_BSSCFG_DEVICE); ++ INIT_IE(assoc_req, P2PAPI_BSSCFG_DEVICE); ++ INIT_IE(assoc_res, P2PAPI_BSSCFG_DEVICE); ++ INIT_IE(beacon, P2PAPI_BSSCFG_DEVICE); ++ INIT_IE(probe_req, P2PAPI_BSSCFG_CONNECTION); ++ INIT_IE(probe_res, P2PAPI_BSSCFG_CONNECTION); ++ INIT_IE(assoc_req, P2PAPI_BSSCFG_CONNECTION); ++ INIT_IE(assoc_res, P2PAPI_BSSCFG_CONNECTION); ++ INIT_IE(beacon, P2PAPI_BSSCFG_CONNECTION); ++#undef INIT_IE ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY) = wl_to_prmry_ndev(wl); ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY) = 0; ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL; ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0; ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = NULL; ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = 0; ++ return BCME_OK; ++ ++} ++/* ++ * Deinitialize variables related to P2P ++ * ++ */ ++void ++wl_cfgp2p_deinit_priv(struct wl_priv *wl) ++{ ++ AP6211_DEBUG("In\n"); ++ if (wl->p2p) { ++ kfree(wl->p2p); ++ wl->p2p = NULL; ++ } ++ wl->p2p_supported = 0; ++} ++/* ++ * Set P2P functions into firmware ++ */ ++s32 ++wl_cfgp2p_set_firm_p2p(struct wl_priv *wl) ++{ ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ struct ether_addr null_eth_addr = { { 0, 0, 0, 0, 0, 0 } }; ++ s32 ret = BCME_OK; ++ s32 val = 0; ++ /* Do we have to check whether APSTA is enabled or not ? */ ++ wldev_iovar_getint(ndev, "apsta", &val); ++ if (val == 0) { ++ val = 1; ++ ret = wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true); ++ if (ret < 0) { ++ AP6211_ERR("WLC_DOWN error %d\n", ret); ++ return ret; ++ } ++ wldev_iovar_setint(ndev, "apsta", val); ++ ret = wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true); ++ if (ret < 0) { ++ AP6211_ERR("WLC_UP error %d\n", ret); ++ return ret; ++ } ++ } ++ ++ /* In case of COB type, firmware has default mac address ++ * After Initializing firmware, we have to set current mac address to ++ * firmware for P2P device address ++ */ ++ ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr, ++ sizeof(null_eth_addr), wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync); ++ if (ret && ret != BCME_UNSUPPORTED) { ++ AP6211_ERR("failed to update device address ret %d\n", ret); ++ } ++ return ret; ++} ++ ++/* Create a new P2P BSS. ++ * Parameters: ++ * @mac : MAC address of the BSS to create ++ * @if_type : interface type: WL_P2P_IF_GO or WL_P2P_IF_CLIENT ++ * @chspec : chspec to use if creating a GO BSS. ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, ++ chanspec_t chspec) ++{ ++ wl_p2p_if_t ifreq; ++ s32 err; ++ u32 scb_timeout = WL_SCB_TIMEOUT; ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ ++ ifreq.type = if_type; ++ ifreq.chspec = chspec; ++ memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); ++ ++ AP6211_DEBUG("---wl p2p_ifadd "MACDBG" %s %u\n", ++ MAC2STRDBG(ifreq.addr.octet), ++ (if_type == WL_P2P_IF_GO) ? "go" : "client", ++ (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT); ++ ++ err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); ++ ++ if (unlikely(err < 0)) ++ AP6211_DEBUG("'wl p2p_ifadd' error %d\n", err); ++ else if (if_type == WL_P2P_IF_GO) { ++ err = wldev_ioctl(ndev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true); ++ if (unlikely(err < 0)) ++ AP6211_DEBUG("'wl scb_timeout' error %d\n", err); ++ } ++ return err; ++} ++ ++/* Disable a P2P BSS. ++ * Parameters: ++ * @mac : MAC address of the BSS to create ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_ifdisable(struct wl_priv *wl, struct ether_addr *mac) ++{ ++ s32 ret; ++ struct net_device *netdev = wl_to_prmry_ndev(wl); ++ ++ AP6211_DEBUG("------primary idx %d : wl p2p_ifdis "MACDBG"\n", ++ netdev->ifindex, MAC2STRDBG(mac->octet)); ++ ret = wldev_iovar_setbuf(netdev, "p2p_ifdis", mac, sizeof(*mac), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); ++ if (unlikely(ret < 0)) { ++ AP6211_DEBUG("'wl p2p_ifdis' error %d\n", ret); ++ } ++ return ret; ++} ++ ++/* Delete a P2P BSS. ++ * Parameters: ++ * @mac : MAC address of the BSS to create ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac) ++{ ++ s32 ret; ++ struct net_device *netdev = wl_to_prmry_ndev(wl); ++ ++ AP6211_DEBUG("------primary idx %d : wl p2p_ifdel "MACDBG"\n", ++ netdev->ifindex, MAC2STRDBG(mac->octet)); ++ ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); ++ if (unlikely(ret < 0)) { ++ AP6211_DEBUG("'wl p2p_ifdel' error %d\n", ret); ++ } ++ return ret; ++} ++ ++/* Change a P2P Role. ++ * Parameters: ++ * @mac : MAC address of the BSS to change a role ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, ++ chanspec_t chspec) ++{ ++ wl_p2p_if_t ifreq; ++ s32 err; ++ u32 scb_timeout = WL_SCB_TIMEOUT; ++ ++ struct net_device *netdev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); ++ ++ ifreq.type = if_type; ++ ifreq.chspec = chspec; ++ memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); ++ ++ AP6211_DEBUG("---wl p2p_ifchange "MACDBG" %s %u" ++ " chanspec 0x%04x\n", MAC2STRDBG(ifreq.addr.octet), ++ (if_type == WL_P2P_IF_GO) ? "go" : "client", ++ (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT, ++ ifreq.chspec); ++ ++ err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); ++ ++ if (unlikely(err < 0)) { ++ AP6211_DEBUG("'wl p2p_ifupd' error %d\n", err); ++ } else if (if_type == WL_P2P_IF_GO) { ++ err = wldev_ioctl(netdev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true); ++ if (unlikely(err < 0)) ++ AP6211_DEBUG("'wl scb_timeout' error %d\n", err); ++ } ++ return err; ++} ++ ++ ++/* Get the index of a created P2P BSS. ++ * Parameters: ++ * @mac : MAC address of the created BSS ++ * @index : output: index of created BSS ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index) ++{ ++ s32 ret; ++ u8 getbuf[64]; ++ struct net_device *dev = wl_to_prmry_ndev(wl); ++ ++ AP6211_DEBUG("---wl p2p_if "MACDBG"\n", MAC2STRDBG(mac->octet)); ++ ++ ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf, ++ sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY), NULL); ++ ++ if (ret == 0) { ++ memcpy(index, getbuf, sizeof(s32)); ++ AP6211_DEBUG("---wl p2p_if ==> %d\n", *index); ++ } ++ ++ return ret; ++} ++ ++static s32 ++wl_cfgp2p_set_discovery(struct wl_priv *wl, s32 on) ++{ ++ s32 ret = BCME_OK; ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ AP6211_DEBUG("enter\n"); ++ ++ ret = wldev_iovar_setint(ndev, "p2p_disc", on); ++ ++ if (unlikely(ret < 0)) { ++ AP6211_ERR("p2p_disc %d error %d\n", on, ret); ++ } ++ ++ return ret; ++} ++ ++/* Set the WL driver's P2P mode. ++ * Parameters : ++ * @mode : is one of WL_P2P_DISC_ST_{SCAN,LISTEN,SEARCH}. ++ * @channel : the channel to listen ++ * @listen_ms : the time (milli seconds) to wait ++ * @bssidx : bss index for BSSCFG ++ * Returns 0 if success ++ */ ++ ++s32 ++wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms, int bssidx) ++{ ++ wl_p2p_disc_st_t discovery_mode; ++ s32 ret; ++ struct net_device *dev; ++ AP6211_DEBUG("enter\n"); ++ ++ if (unlikely(bssidx == WL_INVALID || bssidx >= P2PAPI_BSSCFG_MAX)) { ++ AP6211_ERR(" %d index out of range\n", bssidx); ++ return -1; ++ } ++ ++ dev = wl_to_p2p_bss_ndev(wl, bssidx); ++ if (unlikely(dev == NULL)) { ++ AP6211_ERR("bssidx %d is not assigned\n", bssidx); ++ return BCME_NOTFOUND; ++ } ++ ++ /* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */ ++ discovery_mode.state = mode; ++ discovery_mode.chspec = wl_ch_host_to_driver(channel); ++ discovery_mode.dwell = listen_ms; ++ ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode, ++ sizeof(discovery_mode), wl->ioctl_buf, WLC_IOCTL_MAXLEN, ++ bssidx, &wl->ioctl_buf_sync); ++ ++ return ret; ++} ++ ++/* Get the index of the P2P Discovery BSS */ ++static s32 ++wl_cfgp2p_get_disc_idx(struct wl_priv *wl, s32 *index) ++{ ++ s32 ret; ++ struct net_device *dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); ++ ++ ret = wldev_iovar_getint(dev, "p2p_dev", index); ++ AP6211_DEBUG("p2p_dev bsscfg_idx=%d ret=%d\n", *index, ret); ++ ++ if (unlikely(ret < 0)) { ++ AP6211_ERR("'p2p_dev' error %d\n", ret); ++ return ret; ++ } ++ return ret; ++} ++ ++s32 ++wl_cfgp2p_init_discovery(struct wl_priv *wl) ++{ ++ ++ s32 index = 0; ++ s32 ret = BCME_OK; ++ ++ AP6211_DEBUG("enter\n"); ++ ++ if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) != 0) { ++ AP6211_ERR("do nothing, already initialized\n"); ++ return ret; ++ } ++ ++ ret = wl_cfgp2p_set_discovery(wl, 1); ++ if (ret < 0) { ++ AP6211_ERR("set discover error\n"); ++ return ret; ++ } ++ /* Enable P2P Discovery in the WL Driver */ ++ ret = wl_cfgp2p_get_disc_idx(wl, &index); ++ ++ if (ret < 0) { ++ return ret; ++ } ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = index; ++ ++ /* Set the initial discovery state to SCAN */ ++ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); ++ ++ if (unlikely(ret != 0)) { ++ AP6211_ERR("unable to set WL_P2P_DISC_ST_SCAN\n"); ++ wl_cfgp2p_set_discovery(wl, 0); ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0; ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL; ++ return 0; ++ } ++ return ret; ++} ++ ++/* Deinitialize P2P Discovery ++ * Parameters : ++ * @wl : wl_private data ++ * Returns 0 if succes ++ */ ++static s32 ++wl_cfgp2p_deinit_discovery(struct wl_priv *wl) ++{ ++ s32 ret = BCME_OK; ++ AP6211_DEBUG("enter\n"); ++ ++ if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) == 0) { ++ AP6211_ERR("do nothing, not initialized\n"); ++ return -1; ++ } ++ /* Set the discovery state to SCAN */ ++ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); ++ /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */ ++ ret = wl_cfgp2p_set_discovery(wl, 0); ++ ++ /* Clear our saved WPS and P2P IEs for the discovery BSS. The driver ++ * deleted these IEs when wl_cfgp2p_set_discovery() deleted the discovery ++ * BSS. ++ */ ++ ++ /* Clear the saved bsscfg index of the discovery BSSCFG to indicate we ++ * have no discovery BSS. ++ */ ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = WL_INVALID; ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL; ++ ++ return ret; ++ ++} ++/* Enable P2P Discovery ++ * Parameters: ++ * @wl : wl_private data ++ * @ie : probe request ie (WPS IE + P2P IE) ++ * @ie_len : probe request ie length ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, ++ const u8 *ie, u32 ie_len) ++{ ++ s32 ret = BCME_OK; ++ s32 bssidx = (wl_to_prmry_ndev(wl) == dev) ? ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) : wl_cfgp2p_find_idx(wl, dev); ++ if (wl_get_p2p_status(wl, DISCOVERY_ON)) { ++ AP6211_DEBUG(" DISCOVERY is already initialized, we have nothing to do\n"); ++ goto set_ie; ++ } ++ ++ wl_set_p2p_status(wl, DISCOVERY_ON); ++ ++ AP6211_DEBUG("enter\n"); ++ ++ ret = wl_cfgp2p_init_discovery(wl); ++ if (unlikely(ret < 0)) { ++ AP6211_ERR(" init discovery error %d\n", ret); ++ goto exit; ++ } ++ /* Set wsec to any non-zero value in the discovery bsscfg to ensure our ++ * P2P probe responses have the privacy bit set in the 802.11 WPA IE. ++ * Some peer devices may not initiate WPS with us if this bit is not set. ++ */ ++ ret = wldev_iovar_setint_bsscfg(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), ++ "wsec", AES_ENABLED, wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); ++ if (unlikely(ret < 0)) { ++ AP6211_ERR(" wsec error %d\n", ret); ++ } ++set_ie: ++ if (ie_len) { ++ ret = wl_cfgp2p_set_management_ie(wl, dev, ++ bssidx, ++ VNDR_IE_PRBREQ_FLAG, ie, ie_len); ++ ++ if (unlikely(ret < 0)) { ++ AP6211_ERR("set probreq ie occurs error %d\n", ret); ++ goto exit; ++ } ++ } ++exit: ++ return ret; ++} ++ ++/* Disable P2P Discovery ++ * Parameters: ++ * @wl : wl_private_data ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_disable_discovery(struct wl_priv *wl) ++{ ++ s32 ret = BCME_OK; ++ AP6211_DEBUG(" enter\n"); ++ wl_clr_p2p_status(wl, DISCOVERY_ON); ++ ++ if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) == 0) { ++ AP6211_ERR(" do nothing, not initialized\n"); ++ goto exit; ++ } ++ ++ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); ++ ++ if (unlikely(ret < 0)) { ++ ++ AP6211_ERR("unable to set WL_P2P_DISC_ST_SCAN\n"); ++ } ++ /* Do a scan abort to stop the driver's scan engine in case it is still ++ * waiting out an action frame tx dwell time. ++ */ ++ wl_clr_p2p_status(wl, DISCOVERY_ON); ++ ret = wl_cfgp2p_deinit_discovery(wl); ++ ++exit: ++ return ret; ++} ++ ++s32 ++wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, ++ u32 num_chans, u16 *channels, ++ s32 search_state, u16 action, u32 bssidx) ++{ ++ s32 ret = BCME_OK; ++ s32 memsize; ++ s32 eparams_size; ++ u32 i; ++ s8 *memblk; ++ wl_p2p_scan_t *p2p_params; ++ wl_escan_params_t *eparams; ++ wlc_ssid_t ssid; ++ /* Scan parameters */ ++#define P2PAPI_SCAN_NPROBES 1 ++#define P2PAPI_SCAN_DWELL_TIME_MS 80 ++#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40 ++#define P2PAPI_SCAN_HOME_TIME_MS 60 ++#define P2PAPI_SCAN_NPROBS_TIME_MS 30 ++#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100 ++ ++ struct net_device *pri_dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); ++ /* Allocate scan params which need space for 3 channels and 0 ssids */ ++ eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE + ++ OFFSETOF(wl_escan_params_t, params)) + ++ num_chans * sizeof(eparams->params.channel_list[0]); ++ ++ memsize = sizeof(wl_p2p_scan_t) + eparams_size; ++ memblk = scanparambuf; ++ if (memsize > sizeof(scanparambuf)) { ++ AP6211_ERR(" scanpar buf too small (%u > %u)\n", ++ memsize, sizeof(scanparambuf)); ++ return -1; ++ } ++ memset(memblk, 0, memsize); ++ memset(wl->ioctl_buf, 0, WLC_IOCTL_MAXLEN); ++ if (search_state == WL_P2P_DISC_ST_SEARCH) { ++ /* ++ * If we in SEARCH STATE, we don't need to set SSID explictly ++ * because dongle use P2P WILDCARD internally by default ++ */ ++ wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx); ++ ssid.SSID_len = htod32(0); ++ ++ } else if (search_state == WL_P2P_DISC_ST_SCAN) { ++ /* SCAN STATE 802.11 SCAN ++ * WFD Supplicant has p2p_find command with (type=progressive, type= full) ++ * So if P2P_find command with type=progressive, ++ * we have to set ssid to P2P WILDCARD because ++ * we just do broadcast scan unless setting SSID ++ */ ++ strncpy(ssid.SSID, WL_P2P_WILDCARD_SSID, sizeof(ssid.SSID) - 1); ++ ssid.SSID[sizeof(ssid.SSID) - 1] = 0; ++ ssid.SSID_len = htod32(WL_P2P_WILDCARD_SSID_LEN); ++ wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx); ++ } ++ else { ++ AP6211_ERR(" invalid search state %d\n", search_state); ++ return -1; ++ } ++ ++ ++ /* Fill in the P2P scan structure at the start of the iovar param block */ ++ p2p_params = (wl_p2p_scan_t*) memblk; ++ p2p_params->type = 'E'; ++ /* Fill in the Scan structure that follows the P2P scan structure */ ++ eparams = (wl_escan_params_t*) (p2p_params + 1); ++ eparams->params.bss_type = DOT11_BSSTYPE_ANY; ++ if (active) ++ eparams->params.scan_type = DOT11_SCANTYPE_ACTIVE; ++ else ++ eparams->params.scan_type = DOT11_SCANTYPE_PASSIVE; ++ ++ memcpy(&eparams->params.bssid, ðer_bcast, ETHER_ADDR_LEN); ++ if (ssid.SSID_len) ++ memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t)); ++ ++ eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS); ++ ++ /* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan supported by ++ * the supplicant ++ */ ++ if ((num_chans == SOCIAL_CHAN_CNT) || (num_chans == SOCIAL_CHAN_CNT + 1)) ++ eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS); ++ else if (num_chans == AF_PEER_SEARCH_CNT) ++ eparams->params.active_time = htod32(P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS); ++ else if (wl_get_drv_status_all(wl, CONNECTED)) ++ eparams->params.active_time = -1; ++ else ++ eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS); ++ eparams->params.nprobes = htod32((eparams->params.active_time / ++ P2PAPI_SCAN_NPROBS_TIME_MS)); ++ ++ /* Override scan params to find a peer for a connection */ ++ if (num_chans == 1) { ++ eparams->params.active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); ++ eparams->params.nprobes = htod32(eparams->params.active_time / ++ WL_SCAN_JOIN_PROBE_INTERVAL_MS); ++ } ++ ++ if (eparams->params.nprobes <= 0) ++ eparams->params.nprobes = 1; ++ AP6211_DEBUG("nprobes # %d, active_time %d\n", ++ eparams->params.nprobes, eparams->params.active_time); ++ eparams->params.passive_time = htod32(-1); ++ eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | ++ (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); ++ ++ for (i = 0; i < num_chans; i++) { ++ eparams->params.channel_list[i] = wl_ch_host_to_driver(channels[i]); ++ } ++ eparams->version = htod32(ESCAN_REQ_VERSION); ++ eparams->action = htod16(action); ++ eparams->sync_id = htod16(0x1234); ++ AP6211_DEBUG("SCAN CHANNELS : "); ++ ++ for (i = 0; i < num_chans; i++) { ++ if (i == 0) AP6211_DEBUG("%d", channels[i]); ++ else AP6211_DEBUG(",%d", channels[i]); ++ } ++ ++ AP6211_DEBUG("\n"); ++ ++ ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan", ++ memblk, memsize, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ if (ret == BCME_OK) ++ wl_set_p2p_status(wl, SCANNING); ++ return ret; ++} ++ ++/* search function to reach at common channel to send action frame ++ * Parameters: ++ * @wl : wl_private data ++ * @ndev : net device for bssidx ++ * @bssidx : bssidx for BSS ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev, ++ s32 bssidx, s32 channel) ++{ ++ s32 ret = 0; ++ u32 chan_cnt = 0; ++ u16 *default_chan_list = NULL; ++ if (!p2p_is_on(wl) || ndev == NULL || bssidx == WL_INVALID) ++ return -BCME_ERROR; ++ AP6211_DEBUG(" Enter\n"); ++ if (bssidx == P2PAPI_BSSCFG_PRIMARY) ++ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); ++ if (channel) ++ chan_cnt = AF_PEER_SEARCH_CNT; ++ else ++ chan_cnt = SOCIAL_CHAN_CNT; ++ default_chan_list = kzalloc(chan_cnt * sizeof(*default_chan_list), GFP_KERNEL); ++ if (default_chan_list == NULL) { ++ AP6211_ERR("channel list allocation failed \n"); ++ ret = -ENOMEM; ++ goto exit; ++ } ++ if (channel) { ++ u32 i; ++ /* insert same channel to the chan_list */ ++ for (i = 0; i < chan_cnt; i++) { ++ default_chan_list[i] = channel; ++ } ++ } else { ++ default_chan_list[0] = SOCIAL_CHAN_1; ++ default_chan_list[1] = SOCIAL_CHAN_2; ++ default_chan_list[2] = SOCIAL_CHAN_3; ++ } ++ ret = wl_cfgp2p_escan(wl, ndev, true, chan_cnt, ++ default_chan_list, WL_P2P_DISC_ST_SEARCH, ++ WL_SCAN_ACTION_START, bssidx); ++ kfree(default_chan_list); ++exit: ++ return ret; ++} ++ ++/* Check whether pointed-to IE looks like WPA. */ ++#define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ ++ (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE) ++/* Check whether pointed-to IE looks like WPS. */ ++#define wl_cfgp2p_is_wps_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ ++ (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE) ++/* Check whether the given IE looks like WFA P2P IE. */ ++#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ ++ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P) ++/* Check whether the given IE looks like WFA WFDisplay IE. */ ++#define WFA_OUI_TYPE_WFD 0x0a /* WiFi Display OUI TYPE */ ++#define wl_cfgp2p_is_wfd_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ ++ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_WFD) ++ ++static s32 ++wl_cfgp2p_parse_vndr_ies(u8 *parse, u32 len, ++ struct parsed_vndr_ies *vndr_ies) ++{ ++ s32 err = BCME_OK; ++ vndr_ie_t *vndrie; ++ bcm_tlv_t *ie; ++ struct parsed_vndr_ie_info *parsed_info; ++ u32 count = 0; ++ s32 remained_len; ++ ++ remained_len = (s32)len; ++ memset(vndr_ies, 0, sizeof(*vndr_ies)); ++ ++ AP6211_DEBUG("---> len %d\n", len); ++ ie = (bcm_tlv_t *) parse; ++ if (!bcm_valid_tlv(ie, remained_len)) ++ ie = NULL; ++ while (ie) { ++ if (count >= MAX_VNDR_IE_NUMBER) ++ break; ++ if (ie->id == DOT11_MNG_VS_ID) { ++ vndrie = (vndr_ie_t *) ie; ++ /* len should be bigger than OUI length + one data length at least */ ++ if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) { ++ AP6211_ERR("%s: invalid vndr ie. length is too small %d\n", ++ __FUNCTION__, vndrie->len); ++ goto end; ++ } ++ /* if wpa or wme ie, do not add ie */ ++ if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) && ++ ((vndrie->data[0] == WPA_OUI_TYPE) || ++ (vndrie->data[0] == WME_OUI_TYPE))) { ++ AP6211_DEBUG("Found WPA/WME oui. Do not add it\n"); ++ goto end; ++ } ++ ++ parsed_info = &vndr_ies->ie_info[count++]; ++ ++ /* save vndr ie information */ ++ parsed_info->ie_ptr = (char *)vndrie; ++ parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN); ++ memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t)); ++ ++ vndr_ies->count = count; ++ ++ AP6211_DEBUG("\t ** OUI %02x %02x %02x, type 0x%02x \n", ++ parsed_info->vndrie.oui[0], parsed_info->vndrie.oui[1], ++ parsed_info->vndrie.oui[2], parsed_info->vndrie.data[0]); ++ } ++end: ++ ie = bcm_next_tlv(ie, &remained_len); ++ } ++ return err; ++} ++ ++ ++/* Delete and Set a management vndr ie to firmware ++ * Parameters: ++ * @wl : wl_private data ++ * @ndev : net device for bssidx ++ * @bssidx : bssidx for BSS ++ * @pktflag : packet flag for IE (VNDR_IE_PRBREQ_FLAG,VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, ++ * VNDR_IE_ASSOCREQ_FLAG) ++ * @ie : VNDR IE (such as P2P IE , WPS IE) ++ * @ie_len : VNDR IE Length ++ * Returns 0 if success. ++ */ ++ ++s32 ++wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, ++ s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len) ++{ ++ s32 ret = BCME_OK; ++ u8 *curr_ie_buf = NULL; ++ u8 *mgmt_ie_buf = NULL; ++ u32 mgmt_ie_buf_len = 0; ++ u32 *mgmt_ie_len = 0; ++ u32 del_add_ie_buf_len = 0; ++ u32 total_ie_buf_len = 0; ++ u32 parsed_ie_buf_len = 0; ++ struct parsed_vndr_ies old_vndr_ies; ++ struct parsed_vndr_ies new_vndr_ies; ++ s32 i; ++ u8 *ptr; ++ s32 remained_buf_len; ++ ++#define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie) ++#define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len) ++ memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf)); ++ curr_ie_buf = g_mgmt_ie_buf; ++ AP6211_DEBUG(" bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag); ++ if (wl->p2p != NULL) { ++ switch (pktflag) { ++ case VNDR_IE_PRBREQ_FLAG : ++ mgmt_ie_buf = IE_TYPE(probe_req, bssidx); ++ mgmt_ie_len = &IE_TYPE_LEN(probe_req, bssidx); ++ mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, bssidx)); ++ break; ++ case VNDR_IE_PRBRSP_FLAG : ++ mgmt_ie_buf = IE_TYPE(probe_res, bssidx); ++ mgmt_ie_len = &IE_TYPE_LEN(probe_res, bssidx); ++ mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, bssidx)); ++ break; ++ case VNDR_IE_ASSOCREQ_FLAG : ++ mgmt_ie_buf = IE_TYPE(assoc_req, bssidx); ++ mgmt_ie_len = &IE_TYPE_LEN(assoc_req, bssidx); ++ mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, bssidx)); ++ break; ++ case VNDR_IE_ASSOCRSP_FLAG : ++ mgmt_ie_buf = IE_TYPE(assoc_res, bssidx); ++ mgmt_ie_len = &IE_TYPE_LEN(assoc_res, bssidx); ++ mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, bssidx)); ++ break; ++ case VNDR_IE_BEACON_FLAG : ++ mgmt_ie_buf = IE_TYPE(beacon, bssidx); ++ mgmt_ie_len = &IE_TYPE_LEN(beacon, bssidx); ++ mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, bssidx)); ++ break; ++ default: ++ mgmt_ie_buf = NULL; ++ mgmt_ie_len = NULL; ++ AP6211_ERR("not suitable type\n"); ++ return -1; ++ } ++ } else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { ++ switch (pktflag) { ++ case VNDR_IE_PRBRSP_FLAG : ++ mgmt_ie_buf = wl->ap_info->probe_res_ie; ++ mgmt_ie_len = &wl->ap_info->probe_res_ie_len; ++ mgmt_ie_buf_len = sizeof(wl->ap_info->probe_res_ie); ++ break; ++ case VNDR_IE_BEACON_FLAG : ++ mgmt_ie_buf = wl->ap_info->beacon_ie; ++ mgmt_ie_len = &wl->ap_info->beacon_ie_len; ++ mgmt_ie_buf_len = sizeof(wl->ap_info->beacon_ie); ++ break; ++ default: ++ mgmt_ie_buf = NULL; ++ mgmt_ie_len = NULL; ++ AP6211_ERR("not suitable type\n"); ++ return -1; ++ } ++ bssidx = 0; ++ } else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) { ++ switch (pktflag) { ++ case VNDR_IE_PRBREQ_FLAG : ++ mgmt_ie_buf = wl->sta_info->probe_req_ie; ++ mgmt_ie_len = &wl->sta_info->probe_req_ie_len; ++ mgmt_ie_buf_len = sizeof(wl->sta_info->probe_req_ie); ++ break; ++ case VNDR_IE_ASSOCREQ_FLAG : ++ mgmt_ie_buf = wl->sta_info->assoc_req_ie; ++ mgmt_ie_len = &wl->sta_info->assoc_req_ie_len; ++ mgmt_ie_buf_len = sizeof(wl->sta_info->assoc_req_ie); ++ break; ++ default: ++ mgmt_ie_buf = NULL; ++ mgmt_ie_len = NULL; ++ AP6211_ERR("not suitable type\n"); ++ return -1; ++ } ++ bssidx = 0; ++ } else { ++ AP6211_ERR("not suitable type\n"); ++ return -1; ++ } ++ ++ if (vndr_ie_len > mgmt_ie_buf_len) { ++ AP6211_ERR("extra IE size too big\n"); ++ ret = -ENOMEM; ++ } else { ++ /* parse and save new vndr_ie in curr_ie_buff before comparing it */ ++ if (vndr_ie && vndr_ie_len && curr_ie_buf) { ++ ptr = curr_ie_buf; ++ ++ wl_cfgp2p_parse_vndr_ies((u8*)vndr_ie, ++ vndr_ie_len, &new_vndr_ies); ++ ++ for (i = 0; i < new_vndr_ies.count; i++) { ++ struct parsed_vndr_ie_info *vndrie_info = ++ &new_vndr_ies.ie_info[i]; ++ ++ memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr, ++ vndrie_info->ie_len); ++ parsed_ie_buf_len += vndrie_info->ie_len; ++ } ++ } ++ ++ if (mgmt_ie_buf != NULL) { ++ if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) && ++ (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) { ++ AP6211_DEBUG("Previous mgmt IE is equals to current IE"); ++ goto exit; ++ } ++ ++ /* parse old vndr_ie */ ++ wl_cfgp2p_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, ++ &old_vndr_ies); ++ ++ /* make a command to delete old ie */ ++ for (i = 0; i < old_vndr_ies.count; i++) { ++ struct parsed_vndr_ie_info *vndrie_info = ++ &old_vndr_ies.ie_info[i]; ++ ++ AP6211_DEBUG("DELETED ID : %d, Len: %d , OUI:%02x:%02x:%02x\n", ++ vndrie_info->vndrie.id, vndrie_info->vndrie.len, ++ vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1], ++ vndrie_info->vndrie.oui[2]); ++ ++ del_add_ie_buf_len = wl_cfgp2p_vndr_ie(wl, curr_ie_buf, ++ bssidx, pktflag, vndrie_info->vndrie.oui, ++ vndrie_info->vndrie.id, ++ vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, ++ vndrie_info->ie_len - VNDR_IE_FIXED_LEN, ++ "del"); ++ ++ curr_ie_buf += del_add_ie_buf_len; ++ total_ie_buf_len += del_add_ie_buf_len; ++ } ++ } ++ ++ *mgmt_ie_len = 0; ++ /* Add if there is any extra IE */ ++ if (mgmt_ie_buf && parsed_ie_buf_len) { ++ ptr = mgmt_ie_buf; ++ ++ remained_buf_len = mgmt_ie_buf_len; ++ ++ /* make a command to add new ie */ ++ for (i = 0; i < new_vndr_ies.count; i++) { ++ struct parsed_vndr_ie_info *vndrie_info = ++ &new_vndr_ies.ie_info[i]; ++ ++ AP6211_DEBUG("ADDED ID : %d, Len: %d(%d), OUI:%02x:%02x:%02x\n", ++ vndrie_info->vndrie.id, vndrie_info->vndrie.len, ++ vndrie_info->ie_len - 2, ++ vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1], ++ vndrie_info->vndrie.oui[2]); ++ ++ del_add_ie_buf_len = wl_cfgp2p_vndr_ie(wl, curr_ie_buf, ++ bssidx, pktflag, vndrie_info->vndrie.oui, ++ vndrie_info->vndrie.id, ++ vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, ++ vndrie_info->ie_len - VNDR_IE_FIXED_LEN, ++ "add"); ++ ++ /* verify remained buf size before copy data */ ++ if (remained_buf_len >= vndrie_info->ie_len) { ++ remained_buf_len -= vndrie_info->ie_len; ++ } else { ++ AP6211_ERR("no space in mgmt_ie_buf: pktflag = %d, " ++ "found vndr ies # = %d(cur %d), remained len %d, " ++ "cur mgmt_ie_len %d, new ie len = %d\n", ++ pktflag, new_vndr_ies.count, i, remained_buf_len, ++ *mgmt_ie_len, vndrie_info->ie_len); ++ break; ++ } ++ ++ /* save the parsed IE in wl struct */ ++ memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr, ++ vndrie_info->ie_len); ++ *mgmt_ie_len += vndrie_info->ie_len; ++ ++ curr_ie_buf += del_add_ie_buf_len; ++ total_ie_buf_len += del_add_ie_buf_len; ++ } ++ } ++ if (total_ie_buf_len) { ++ ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf, ++ total_ie_buf_len, wl->ioctl_buf, WLC_IOCTL_MAXLEN, ++ bssidx, &wl->ioctl_buf_sync); ++ if (ret) ++ AP6211_ERR("vndr ie set error : %d\n", ret); ++ } ++ } ++#undef IE_TYPE ++#undef IE_TYPE_LEN ++exit: ++ return ret; ++} ++ ++/* Clear the manament IE buffer of BSSCFG ++ * Parameters: ++ * @wl : wl_private data ++ * @bssidx : bssidx for BSS ++ * ++ * Returns 0 if success. ++ */ ++s32 ++wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx) ++{ ++ s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, ++ VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG}; ++ s32 index = -1; ++ struct net_device *ndev = wl_cfgp2p_find_ndev(wl, bssidx); ++#define INIT_IE(IE_TYPE, BSS_TYPE) \ ++ do { \ ++ memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ ++ sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \ ++ wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \ ++ } while (0); ++ ++ if (bssidx < 0 || ndev == NULL) { ++ AP6211_ERR("invalid %s\n", (bssidx < 0) ? "bssidx" : "ndev"); ++ return BCME_BADARG; ++ } ++ for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) { ++ /* clean up vndr ies in dongle */ ++ wl_cfgp2p_set_management_ie(wl, ndev, bssidx, vndrie_flag[index], NULL, 0); ++ } ++ INIT_IE(probe_req, bssidx); ++ INIT_IE(probe_res, bssidx); ++ INIT_IE(assoc_req, bssidx); ++ INIT_IE(assoc_res, bssidx); ++ INIT_IE(beacon, bssidx); ++ return BCME_OK; ++} ++ ++ ++/* Is any of the tlvs the expected entry? If ++ * not update the tlvs buffer pointer/length. ++ */ ++static bool ++wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type) ++{ ++ /* If the contents match the OUI and the type */ ++ if (ie[TLV_LEN_OFF] >= oui_len + 1 && ++ !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) && ++ type == ie[TLV_BODY_OFF + oui_len]) { ++ return TRUE; ++ } ++ ++ if (tlvs == NULL) ++ return FALSE; ++ /* point to the next ie */ ++ ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; ++ /* calculate the length of the rest of the buffer */ ++ *tlvs_len -= (int)(ie - *tlvs); ++ /* update the pointer to the start of the buffer */ ++ *tlvs = ie; ++ ++ return FALSE; ++} ++ ++wpa_ie_fixed_t * ++wl_cfgp2p_find_wpaie(u8 *parse, u32 len) ++{ ++ bcm_tlv_t *ie; ++ ++ while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) { ++ if (wl_cfgp2p_is_wpa_ie((u8*)ie, &parse, &len)) { ++ return (wpa_ie_fixed_t *)ie; ++ } ++ } ++ return NULL; ++} ++ ++wpa_ie_fixed_t * ++wl_cfgp2p_find_wpsie(u8 *parse, u32 len) ++{ ++ bcm_tlv_t *ie; ++ ++ while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) { ++ if (wl_cfgp2p_is_wps_ie((u8*)ie, &parse, &len)) { ++ return (wpa_ie_fixed_t *)ie; ++ } ++ } ++ return NULL; ++} ++ ++wifi_p2p_ie_t * ++wl_cfgp2p_find_p2pie(u8 *parse, u32 len) ++{ ++ bcm_tlv_t *ie; ++ ++ while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { ++ if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len)) { ++ return (wifi_p2p_ie_t *)ie; ++ } ++ } ++ return NULL; ++} ++ ++wifi_wfd_ie_t * ++wl_cfgp2p_find_wfdie(u8 *parse, u32 len) ++{ ++ bcm_tlv_t *ie; ++ ++ while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { ++ if (wl_cfgp2p_is_wfd_ie((uint8*)ie, &parse, &len)) { ++ return (wifi_wfd_ie_t *)ie; ++ } ++ } ++ return NULL; ++} ++static u32 ++wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 bssidx, s32 pktflag, ++ s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd) ++{ ++ vndr_ie_setbuf_t hdr; /* aligned temporary vndr_ie buffer header */ ++ s32 iecount; ++ u32 data_offset; ++ ++ /* Validate the pktflag parameter */ ++ if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | ++ VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | ++ VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG))) { ++ AP6211_ERR("p2pwl_vndr_ie: Invalid packet flag 0x%x\n", pktflag); ++ return -1; ++ } ++ ++ /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ ++ strncpy(hdr.cmd, add_del_cmd, VNDR_IE_CMD_LEN - 1); ++ hdr.cmd[VNDR_IE_CMD_LEN - 1] = '\0'; ++ ++ /* Set the IE count - the buffer contains only 1 IE */ ++ iecount = htod32(1); ++ memcpy((void *)&hdr.vndr_ie_buffer.iecount, &iecount, sizeof(s32)); ++ ++ /* Copy packet flags that indicate which packets will contain this IE */ ++ pktflag = htod32(pktflag); ++ memcpy((void *)&hdr.vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, ++ sizeof(u32)); ++ ++ /* Add the IE ID to the buffer */ ++ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id; ++ ++ /* Add the IE length to the buffer */ ++ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = ++ (uint8) VNDR_IE_MIN_LEN + datalen; ++ ++ /* Add the IE OUI to the buffer */ ++ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[0] = oui[0]; ++ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[1] = oui[1]; ++ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[2] = oui[2]; ++ ++ /* Copy the aligned temporary vndr_ie buffer header to the IE buffer */ ++ memcpy(iebuf, &hdr, sizeof(hdr) - 1); ++ ++ /* Copy the IE data to the IE buffer */ ++ data_offset = ++ (u8*)&hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0] - ++ (u8*)&hdr; ++ memcpy(iebuf + data_offset, data, datalen); ++ return data_offset + datalen; ++ ++} ++ ++/* ++ * Search the bssidx based on dev argument ++ * Parameters: ++ * @wl : wl_private data ++ * @ndev : net device to search bssidx ++ * Returns bssidx for ndev ++ */ ++s32 ++wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev) ++{ ++ u32 i; ++ s32 index = -1; ++ ++ if (ndev == NULL) { ++ AP6211_ERR(" ndev is NULL\n"); ++ goto exit; ++ } ++ if (!wl->p2p_supported) { ++ return P2PAPI_BSSCFG_PRIMARY; ++ } ++ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { ++ if (ndev == wl_to_p2p_bss_ndev(wl, i)) { ++ index = wl_to_p2p_bss_bssidx(wl, i); ++ break; ++ } ++ } ++ if (index == -1) ++ return P2PAPI_BSSCFG_PRIMARY; ++exit: ++ return index; ++} ++ ++struct net_device * ++wl_cfgp2p_find_ndev(struct wl_priv *wl, s32 bssidx) ++{ ++ u32 i; ++ struct net_device *ndev = NULL; ++ if (bssidx < 0) { ++ AP6211_ERR(" bsscfg idx is invalid\n"); ++ goto exit; ++ } ++ ++ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { ++ if (bssidx == wl_to_p2p_bss_bssidx(wl, i)) { ++ ndev = wl_to_p2p_bss_ndev(wl, i); ++ break; ++ } ++ } ++ ++exit: ++ return ndev; ++} ++ ++/* ++ * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE ++ */ ++s32 ++wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ s32 ret = BCME_OK; ++ struct net_device *netdev; ++ if (!wl || !wl->p2p) ++ return BCME_ERROR; ++ if (wl->p2p_net == ndev) { ++ netdev = wl_to_prmry_ndev(wl); ++ } else { ++ netdev = ndev; ++ } ++ AP6211_DEBUG(" Enter\n"); ++ if (wl_get_p2p_status(wl, LISTEN_EXPIRED) == 0) { ++ wl_set_p2p_status(wl, LISTEN_EXPIRED); ++ if (timer_pending(&wl->p2p->listen_timer)) { ++ del_timer_sync(&wl->p2p->listen_timer); ++ } ++ ++ if (wl->afx_hdl->is_listen == TRUE && ++ wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { ++ AP6211_DEBUG("Listen DONE for action frame\n"); ++ complete(&wl->act_frm_scan); ++ } ++#ifdef WL_CFG80211_SYNC_GON ++ else if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) { ++ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM_LISTEN, netdev); ++ AP6211_DEBUG("Listen DONE and wake up wait_next_af !!(%d)\n", ++ jiffies_to_msecs(jiffies - wl->af_tx_sent_jiffies)); ++ ++ if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM)) ++ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, netdev); ++ ++ complete(&wl->wait_next_af); ++ } ++#endif /* WL_CFG80211_SYNC_GON */ ++ ++#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ if (wl_get_drv_status_all(wl, REMAINING_ON_CHANNEL)) { ++#else ++ if (wl_get_drv_status_all(wl, REMAINING_ON_CHANNEL) || ++ wl_get_drv_status_all(wl, FAKE_REMAINING_ON_CHANNEL)) { ++#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ AP6211_DEBUG("Listen DONE for ramain on channel expired\n"); ++ wl_clr_drv_status(wl, REMAINING_ON_CHANNEL, netdev); ++#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ wl_clr_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, netdev); ++#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ if (ndev && (ndev->ieee80211_ptr != NULL)) { ++ cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, ++ &wl->remain_on_chan, wl->remain_on_chan_type, GFP_KERNEL); ++ } ++ } ++ if (wl_add_remove_eventmsg(wl_to_prmry_ndev(wl), ++ WLC_E_P2P_PROBREQ_MSG, false) != BCME_OK) { ++ AP6211_ERR(" failed to unset WLC_E_P2P_PROPREQ_MSG\n"); ++ } ++ } else ++ wl_clr_p2p_status(wl, LISTEN_EXPIRED); ++ ++ return ret; ++ ++} ++ ++/* ++ * Timer expire callback function for LISTEN ++ * We can't report cfg80211_remain_on_channel_expired from Timer ISR context, ++ * so lets do it from thread context. ++ */ ++void ++wl_cfgp2p_listen_expired(unsigned long data) ++{ ++ wl_event_msg_t msg; ++ struct wl_priv *wl = (struct wl_priv *) data; ++ AP6211_DEBUG(" Enter\n"); ++ bzero(&msg, sizeof(wl_event_msg_t)); ++ msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE); ++ wl_cfg80211_event(wl->p2p_net ? wl->p2p_net : ++ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), &msg, NULL); ++} ++/* ++ * Routine for cancelling the P2P LISTEN ++ */ ++static s32 ++wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev, ++ bool notify) ++{ ++ AP6211_DEBUG("Enter \n"); ++ /* Irrespective of whether timer is running or not, reset ++ * the LISTEN state. ++ */ ++ if (timer_pending(&wl->p2p->listen_timer)) { ++ del_timer_sync(&wl->p2p->listen_timer); ++ if (notify) ++ if (ndev && ndev->ieee80211_ptr) { ++ cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, ++ &wl->remain_on_chan, wl->remain_on_chan_type, ++ GFP_KERNEL); ++ } ++ } ++ return 0; ++} ++/* ++ * Do a P2P Listen on the given channel for the given duration. ++ * A listen consists of sitting idle and responding to P2P probe requests ++ * with a P2P probe response. ++ * ++ * This fn assumes dongle p2p device discovery is already enabled. ++ * Parameters : ++ * @wl : wl_private data ++ * @channel : channel to listen ++ * @duration_ms : the time (milli seconds) to wait ++ */ ++s32 ++wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms) ++{ ++#define EXTRA_DELAY_TIME 100 ++ s32 ret = BCME_OK; ++ struct timer_list *_timer; ++ s32 extra_delay; ++ struct net_device *netdev = wl_to_prmry_ndev(wl); ++ ++ AP6211_DEBUG(" Enter Listen Channel : %d, Duration : %d\n", channel, duration_ms); ++ if (unlikely(wl_get_p2p_status(wl, DISCOVERY_ON) == 0)) { ++ ++ AP6211_ERR(" Discovery is not set, so we have noting to do\n"); ++ ++ ret = BCME_NOTREADY; ++ goto exit; ++ } ++ if (timer_pending(&wl->p2p->listen_timer)) { ++ AP6211_DEBUG("previous LISTEN is not completed yet\n"); ++ goto exit; ++ ++ } ++#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ else ++ wl_clr_p2p_status(wl, LISTEN_EXPIRED); ++#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ if (wl_add_remove_eventmsg(netdev, WLC_E_P2P_PROBREQ_MSG, true) != BCME_OK) { ++ AP6211_ERR(" failed to set WLC_E_P2P_PROPREQ_MSG\n"); ++ } ++ ++ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms, ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); ++ _timer = &wl->p2p->listen_timer; ++ ++ /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle , ++ * otherwise we will wait up to duration_ms + 100ms + duration / 10 ++ */ ++ if (ret == BCME_OK) { ++ extra_delay = EXTRA_DELAY_TIME + (duration_ms / 10); ++ } else { ++ /* if failed to set listen, it doesn't need to wait whole duration. */ ++ duration_ms = 100 + duration_ms / 20; ++ extra_delay = 0; ++ } ++ ++ INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, extra_delay); ++#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ wl_clr_p2p_status(wl, LISTEN_EXPIRED); ++#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ ++ ++#undef EXTRA_DELAY_TIME ++exit: ++ return ret; ++} ++ ++ ++s32 ++wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 enable) ++{ ++ s32 ret = BCME_OK; ++ AP6211_DEBUG(" Enter\n"); ++ if (!wl_get_p2p_status(wl, DISCOVERY_ON)) { ++ ++ AP6211_DEBUG(" do nothing, discovery is off\n"); ++ return ret; ++ } ++ if (wl_get_p2p_status(wl, SEARCH_ENABLED) == enable) { ++ AP6211_DEBUG("already : %d\n", enable); ++ return ret; ++ } ++ ++ wl_chg_p2p_status(wl, SEARCH_ENABLED); ++ /* When disabling Search, reset the WL driver's p2p discovery state to ++ * WL_P2P_DISC_ST_SCAN. ++ */ ++ if (!enable) { ++ wl_clr_p2p_status(wl, SCANNING); ++ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, ++ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); ++ } ++ ++ return ret; ++} ++ ++/* ++ * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE ++ */ ++s32 ++wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data) ++{ ++ s32 ret = BCME_OK; ++ u32 event_type = ntoh32(e->event_type); ++ u32 status = ntoh32(e->status); ++ AP6211_DEBUG(" Enter\n"); ++ if (event_type == WLC_E_ACTION_FRAME_COMPLETE) { ++ ++ AP6211_DEBUG(" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status); ++ if (status == WLC_E_STATUS_SUCCESS) { ++ wl_set_p2p_status(wl, ACTION_TX_COMPLETED); ++ AP6211_DEBUG("WLC_E_ACTION_FRAME_COMPLETE : ACK\n"); ++ } ++ else { ++ wl_set_p2p_status(wl, ACTION_TX_NOACK); ++ AP6211_DEBUG("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n"); ++ wl_stop_wait_next_action_frame(wl, ndev); ++ } ++ } else { ++ AP6211_DEBUG(" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received," ++ "status : %d\n", status); ++ ++ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) ++ complete(&wl->send_af_done); ++ } ++ return ret; ++} ++/* Send an action frame immediately without doing channel synchronization. ++ * ++ * This function does not wait for a completion event before returning. ++ * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action ++ * frame is transmitted. ++ * The WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE event will be received when an ++ * 802.11 ack has been received for the sent action frame. ++ */ ++s32 ++wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, ++ wl_af_params_t *af_params, s32 bssidx) ++{ ++ s32 ret = BCME_OK; ++ s32 timeout = 0; ++ wl_eventmsg_buf_t buf; ++ ++ ++ AP6211_DEBUG("\n"); ++ AP6211_DEBUG("channel : %u , dwell time : %u\n", ++ af_params->channel, af_params->dwell_time); ++ ++ wl_clr_p2p_status(wl, ACTION_TX_COMPLETED); ++ wl_clr_p2p_status(wl, ACTION_TX_NOACK); ++ ++ bzero(&buf, sizeof(wl_eventmsg_buf_t)); ++ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, true); ++ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, true); ++ if ((ret = wl_cfg80211_apply_eventbuffer(wl_to_prmry_ndev(wl), wl, &buf)) < 0) ++ return ret; ++ ++#define MAX_WAIT_TIME 2000 ++ if (bssidx == P2PAPI_BSSCFG_PRIMARY) ++ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); ++ ++ wl->af_sent_channel = af_params->channel; ++#ifdef WL_CFG80211_SYNC_GON ++ wl->af_tx_sent_jiffies = jiffies; ++#endif /* WL_CFG80211_SYNC_GON */ ++ ++ ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); ++ ++ if (ret < 0) { ++ AP6211_ERR(" sending action frame is failed\n"); ++ goto exit; ++ } ++ ++ timeout = wait_for_completion_timeout(&wl->send_af_done, msecs_to_jiffies(MAX_WAIT_TIME)); ++ ++ if (timeout > 0 && wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) { ++ AP6211_DEBUG("tx action frame operation is completed\n"); ++ ret = BCME_OK; ++ } else { ++ ret = BCME_ERROR; ++ AP6211_DEBUG("tx action frame operation is failed\n"); ++ } ++ /* clear status bit for action tx */ ++ wl_clr_p2p_status(wl, ACTION_TX_COMPLETED); ++ wl_clr_p2p_status(wl, ACTION_TX_NOACK); ++ ++exit: ++ AP6211_DEBUG(" via act frame iovar : status = %d\n", ret); ++ ++ bzero(&buf, sizeof(wl_eventmsg_buf_t)); ++ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, false); ++ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, false); ++ if ((ret = wl_cfg80211_apply_eventbuffer(wl_to_prmry_ndev(wl), wl, &buf)) < 0) ++ AP6211_ERR("TX frame events revert back failed \n"); ++ ++#undef MAX_WAIT_TIME ++ return ret; ++} ++ ++/* Generate our P2P Device Address and P2P Interface Address from our primary ++ * MAC address. ++ */ ++void ++wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, ++ struct ether_addr *out_dev_addr, struct ether_addr *out_int_addr) ++{ ++ memset(out_dev_addr, 0, sizeof(*out_dev_addr)); ++ memset(out_int_addr, 0, sizeof(*out_int_addr)); ++ ++ /* Generate the P2P Device Address. This consists of the device's ++ * primary MAC address with the locally administered bit set. ++ */ ++ memcpy(out_dev_addr, primary_addr, sizeof(*out_dev_addr)); ++ out_dev_addr->octet[0] |= 0x02; ++ ++ /* Generate the P2P Interface Address. If the discovery and connection ++ * BSSCFGs need to simultaneously co-exist, then this address must be ++ * different from the P2P Device Address. ++ */ ++ memcpy(out_int_addr, out_dev_addr, sizeof(*out_int_addr)); ++ out_int_addr->octet[4] ^= 0x80; ++ ++} ++ ++/* P2P IF Address change to Virtual Interface MAC Address */ ++void ++wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id) ++{ ++ wifi_p2p_ie_t *ie = (wifi_p2p_ie_t*) buf; ++ u16 len = ie->len; ++ u8 *subel; ++ u8 subelt_id; ++ u16 subelt_len; ++ AP6211_DEBUG(" Enter\n"); ++ ++ /* Point subel to the P2P IE's subelt field. ++ * Subtract the preceding fields (id, len, OUI, oui_type) from the length. ++ */ ++ subel = ie->subelts; ++ len -= 4; /* exclude OUI + OUI_TYPE */ ++ ++ while (len >= 3) { ++ /* attribute id */ ++ subelt_id = *subel; ++ subel += 1; ++ len -= 1; ++ ++ /* 2-byte little endian */ ++ subelt_len = *subel++; ++ subelt_len |= *subel++ << 8; ++ ++ len -= 2; ++ len -= subelt_len; /* for the remaining subelt fields */ ++ ++ if (subelt_id == element_id) { ++ if (subelt_id == P2P_SEID_INTINTADDR) { ++ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); ++ AP6211_DEBUG("Intended P2P Interface Address ATTR FOUND\n"); ++ } else if (subelt_id == P2P_SEID_DEV_ID) { ++ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); ++ AP6211_DEBUG("Device ID ATTR FOUND\n"); ++ } else if (subelt_id == P2P_SEID_DEV_INFO) { ++ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); ++ AP6211_DEBUG("Device INFO ATTR FOUND\n"); ++ } else if (subelt_id == P2P_SEID_GROUP_ID) { ++ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); ++ AP6211_DEBUG("GROUP ID ATTR FOUND\n"); ++ } return; ++ } else { ++ AP6211_DEBUG("OTHER id : %d\n", subelt_id); ++ } ++ subel += subelt_len; ++ } ++} ++/* ++ * Check if a BSS is up. ++ * This is a common implementation called by most OSL implementations of ++ * p2posl_bss_isup(). DO NOT call this function directly from the ++ * common code -- call p2posl_bss_isup() instead to allow the OSL to ++ * override the common implementation if necessary. ++ */ ++bool ++wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx) ++{ ++ s32 result, val; ++ bool isup = false; ++ s8 getbuf[64]; ++ ++ /* Check if the BSS is up */ ++ *(int*)getbuf = -1; ++ result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx, ++ sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL); ++ if (result != 0) { ++ AP6211_ERR("'wl bss -C %d' failed: %d\n", bsscfg_idx, result); ++ AP6211_ERR("NOTE: this ioctl error is normal " ++ "when the BSS has not been created yet.\n"); ++ } else { ++ val = *(int*)getbuf; ++ val = dtoh32(val); ++ AP6211_DEBUG("---wl bss -C %d ==> %d\n", bsscfg_idx, val); ++ isup = (val ? TRUE : FALSE); ++ } ++ return isup; ++} ++ ++ ++/* Bring up or down a BSS */ ++s32 ++wl_cfgp2p_bss(struct wl_priv *wl, struct net_device *ndev, s32 bsscfg_idx, s32 up) ++{ ++ s32 ret = BCME_OK; ++ s32 val = up ? 1 : 0; ++ ++ struct { ++ s32 cfg; ++ s32 val; ++ } bss_setbuf; ++ ++ bss_setbuf.cfg = htod32(bsscfg_idx); ++ bss_setbuf.val = htod32(val); ++ AP6211_DEBUG("---wl bss -C %d %s\n", bsscfg_idx, up ? "up" : "down"); ++ ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); ++ ++ if (ret != 0) { ++ AP6211_ERR("'bss %d' failed with %d\n", up, ret); ++ } ++ ++ return ret; ++} ++ ++/* Check if 'p2p' is supported in the driver */ ++s32 ++wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev) ++{ ++ s32 ret = BCME_OK; ++ s32 p2p_supported = 0; ++ ret = wldev_iovar_getint(ndev, "p2p", ++ &p2p_supported); ++ if (ret < 0) { ++ AP6211_ERR("wl p2p error %d\n", ret); ++ return 0; ++ } ++ if (p2p_supported == 1) { ++ AP6211_DEBUG("p2p is supported\n"); ++ } else { ++ AP6211_DEBUG("p2p is unsupported\n"); ++ p2p_supported = 0; ++ } ++ return p2p_supported; ++} ++ ++/* Cleanup P2P resources */ ++s32 ++wl_cfgp2p_down(struct wl_priv *wl) ++{ ++ s32 i = 0, index = -1; ++ wl_cfgp2p_cancel_listen(wl, ++ wl->p2p_net ? wl->p2p_net : wl_to_prmry_ndev(wl), TRUE); ++ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { ++ index = wl_to_p2p_bss_bssidx(wl, i); ++ if (index != WL_INVALID) ++ wl_cfgp2p_clear_management_ie(wl, index); ++ } ++ wl_cfgp2p_deinit_priv(wl); ++ return 0; ++} ++ ++s32 ++wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) ++{ ++ s32 ret = -1; ++ int count, start, duration; ++ wl_p2p_sched_t dongle_noa; ++ ++ AP6211_DEBUG(" Enter\n"); ++ ++ memset(&dongle_noa, 0, sizeof(dongle_noa)); ++ ++ if (wl->p2p && wl->p2p->vif_created) { ++ ++ wl->p2p->noa.desc[0].start = 0; ++ ++ sscanf(buf, "%10d %10d %10d", &count, &start, &duration); ++ AP6211_DEBUG("set_p2p_noa count %d start %d duration %d\n", ++ count, start, duration); ++ if (count != -1) ++ wl->p2p->noa.desc[0].count = count; ++ ++ /* supplicant gives interval as start */ ++ if (start != -1) ++ wl->p2p->noa.desc[0].interval = start; ++ ++ if (duration != -1) ++ wl->p2p->noa.desc[0].duration = duration; ++ ++ if (wl->p2p->noa.desc[0].count != 255) { ++ wl->p2p->noa.desc[0].start = 200; ++ dongle_noa.type = WL_P2P_SCHED_TYPE_REQ_ABS; ++ dongle_noa.action = WL_P2P_SCHED_ACTION_GOOFF; ++ dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS; ++ } ++ else { ++ /* Continuous NoA interval. */ ++ dongle_noa.action = WL_P2P_SCHED_ACTION_NONE; ++ dongle_noa.type = WL_P2P_SCHED_TYPE_ABS; ++ if ((wl->p2p->noa.desc[0].interval == 102) || ++ (wl->p2p->noa.desc[0].interval == 100)) { ++ wl->p2p->noa.desc[0].start = 100 - ++ wl->p2p->noa.desc[0].duration; ++ dongle_noa.option = WL_P2P_SCHED_OPTION_BCNPCT; ++ } ++ else { ++ dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL; ++ } ++ } ++ /* Put the noa descriptor in dongle format for dongle */ ++ dongle_noa.desc[0].count = htod32(wl->p2p->noa.desc[0].count); ++ if (dongle_noa.option == WL_P2P_SCHED_OPTION_BCNPCT) { ++ dongle_noa.desc[0].start = htod32(wl->p2p->noa.desc[0].start); ++ dongle_noa.desc[0].duration = htod32(wl->p2p->noa.desc[0].duration); ++ } ++ else { ++ dongle_noa.desc[0].start = htod32(wl->p2p->noa.desc[0].start*1000); ++ dongle_noa.desc[0].duration = htod32(wl->p2p->noa.desc[0].duration*1000); ++ } ++ dongle_noa.desc[0].interval = htod32(wl->p2p->noa.desc[0].interval*1000); ++ ++ ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION), ++ "p2p_noa", &dongle_noa, sizeof(dongle_noa), wl->ioctl_buf, WLC_IOCTL_MAXLEN, ++ &wl->ioctl_buf_sync); ++ ++ if (ret < 0) { ++ AP6211_ERR("fw set p2p_noa failed %d\n", ret); ++ } ++ } ++ else { ++ AP6211_ERR("ERROR: set_noa in non-p2p mode\n"); ++ } ++ return ret; ++} ++s32 ++wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int buf_len) ++{ ++ ++ wifi_p2p_noa_desc_t *noa_desc; ++ int len = 0, i; ++ char _buf[200]; ++ ++ AP6211_DEBUG(" Enter\n"); ++ buf[0] = '\0'; ++ if (wl->p2p && wl->p2p->vif_created) { ++ if (wl->p2p->noa.desc[0].count || wl->p2p->ops.ops) { ++ _buf[0] = 1; /* noa index */ ++ _buf[1] = (wl->p2p->ops.ops ? 0x80: 0) | ++ (wl->p2p->ops.ctw & 0x7f); /* ops + ctw */ ++ len += 2; ++ if (wl->p2p->noa.desc[0].count) { ++ noa_desc = (wifi_p2p_noa_desc_t*)&_buf[len]; ++ noa_desc->cnt_type = wl->p2p->noa.desc[0].count; ++ noa_desc->duration = wl->p2p->noa.desc[0].duration; ++ noa_desc->interval = wl->p2p->noa.desc[0].interval; ++ noa_desc->start = wl->p2p->noa.desc[0].start; ++ len += sizeof(wifi_p2p_noa_desc_t); ++ } ++ if (buf_len <= len * 2) { ++ AP6211_ERR("ERROR: buf_len %d in not enough for" ++ "returning noa in string format\n", buf_len); ++ return -1; ++ } ++ /* We have to convert the buffer data into ASCII strings */ ++ for (i = 0; i < len; i++) { ++ snprintf(buf, 3, "%02x", _buf[i]); ++ buf += 2; ++ } ++ buf[i*2] = '\0'; ++ } ++ } ++ else { ++ AP6211_ERR("ERROR: get_noa in non-p2p mode\n"); ++ return -1; ++ } ++ return len * 2; ++} ++s32 ++wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) ++{ ++ int ps, ctw; ++ int ret = -1; ++ s32 legacy_ps; ++ ++ AP6211_DEBUG(" Enter\n"); ++ if (wl->p2p && wl->p2p->vif_created) { ++ sscanf(buf, "%10d %10d %10d", &legacy_ps, &ps, &ctw); ++ AP6211_DEBUG(" Enter legacy_ps %d ps %d ctw %d\n", legacy_ps, ps, ctw); ++ if (ctw != -1) { ++ wl->p2p->ops.ctw = ctw; ++ ret = 0; ++ } ++ if (ps != -1) { ++ wl->p2p->ops.ops = ps; ++ ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION), ++ "p2p_ops", &wl->p2p->ops, sizeof(wl->p2p->ops), ++ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); ++ if (ret < 0) { ++ AP6211_ERR("fw set p2p_ops failed %d\n", ret); ++ } ++ } ++ ++ if ((legacy_ps != -1) && ((legacy_ps == PM_MAX) || (legacy_ps == PM_OFF))) { ++#if !defined(SUPPORT_PM2_ONLY) ++ if (legacy_ps == PM_MAX) ++ legacy_ps = PM_FAST; ++#endif /* SUPPORT_PM2_ONLY */ ++ ++ ret = wldev_ioctl(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION), ++ WLC_SET_PM, &legacy_ps, sizeof(legacy_ps), true); ++ if (unlikely(ret)) { ++ AP6211_ERR("error (%d)\n", ret); ++ } else { ++ wl_cfg80211_update_power_mode(ndev); ++ } ++ } ++ else ++ AP6211_ERR("ilegal setting\n"); ++ } ++ else { ++ AP6211_ERR("ERROR: set_p2p_ps in non-p2p mode\n"); ++ ret = -1; ++ } ++ return ret; ++} ++ ++u8 * ++wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id) ++{ ++ wifi_p2p_ie_t *ie = NULL; ++ u16 len = 0; ++ u8 *subel; ++ u8 subelt_id; ++ u16 subelt_len; ++ ++ if (!buf) { ++ AP6211_ERR("P2P IE not present"); ++ return 0; ++ } ++ ++ ie = (wifi_p2p_ie_t*) buf; ++ len = ie->len; ++ ++ /* Point subel to the P2P IE's subelt field. ++ * Subtract the preceding fields (id, len, OUI, oui_type) from the length. ++ */ ++ subel = ie->subelts; ++ len -= 4; /* exclude OUI + OUI_TYPE */ ++ ++ while (len >= 3) { ++ /* attribute id */ ++ subelt_id = *subel; ++ subel += 1; ++ len -= 1; ++ ++ /* 2-byte little endian */ ++ subelt_len = *subel++; ++ subelt_len |= *subel++ << 8; ++ ++ len -= 2; ++ len -= subelt_len; /* for the remaining subelt fields */ ++ ++ if (subelt_id == element_id) { ++ /* This will point to start of subelement attrib after ++ * attribute id & len ++ */ ++ return subel; ++ } ++ ++ /* Go to next subelement */ ++ subel += subelt_len; ++ } ++ ++ /* Not Found */ ++ return NULL; ++} ++ ++#define P2P_GROUP_CAPAB_GO_BIT 0x01 ++u8 * ++wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length) ++{ ++ wifi_p2p_ie_t * p2p_ie = NULL; ++ u8 *capability = NULL; ++ bool p2p_go = 0; ++ u8 *ptr = NULL; ++ ++ if (!(p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, bi->ie_length))) { ++ AP6211_ERR("P2P IE not found"); ++ return NULL; ++ } ++ ++ if (!(capability = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_P2P_INFO))) { ++ AP6211_ERR("P2P Capability attribute not found"); ++ return NULL; ++ } ++ ++ /* Check Group capability for Group Owner bit */ ++ p2p_go = capability[1] & P2P_GROUP_CAPAB_GO_BIT; ++ if (!p2p_go) { ++ return bi->BSSID.octet; ++ } ++ ++ /* In probe responses, DEVICE INFO attribute will be present */ ++ if (!(ptr = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_INFO))) { ++ /* If DEVICE_INFO is not found, this might be a beacon frame. ++ * check for DEVICE_ID in the beacon frame. ++ */ ++ ptr = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_ID); ++ } ++ ++ if (!ptr) ++ AP6211_ERR(" Both DEVICE_ID & DEVICE_INFO attribute not present in P2P IE "); ++ ++ return ptr; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) ++static void ++wl_cfgp2p_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) ++{ ++ snprintf(info->driver, sizeof(info->driver), "p2p"); ++ snprintf(info->version, sizeof(info->version), "%lu", (unsigned long)(0)); ++} ++ ++struct ethtool_ops cfgp2p_ethtool_ops = { ++ .get_drvinfo = wl_cfgp2p_ethtool_get_drvinfo ++}; ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ ++ ++s32 ++wl_cfgp2p_register_ndev(struct wl_priv *wl) ++{ ++ int ret = 0; ++ struct net_device* net = NULL; ++ struct wireless_dev *wdev = NULL; ++ uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 }; ++ ++ if (wl->p2p_net) { ++ AP6211_ERR("p2p_net defined already.\n"); ++ return -EINVAL; ++ } ++ ++ /* Allocate etherdev, including space for private structure */ ++ if (!(net = alloc_etherdev(sizeof(struct wl_priv *)))) { ++ AP6211_ERR("%s: OOM - alloc_etherdev\n", __FUNCTION__); ++ return -ENODEV; ++ } ++ ++ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); ++ if (unlikely(!wdev)) { ++ AP6211_ERR("Could not allocate wireless device\n"); ++ free_netdev(net); ++ return -ENOMEM; ++ } ++ ++ strncpy(net->name, "p2p%d", sizeof(net->name) - 1); ++ net->name[IFNAMSIZ - 1] = '\0'; ++ ++ /* Copy the reference to wl_priv */ ++ memcpy((void *)netdev_priv(net), &wl, sizeof(struct wl_priv *)); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ++ ASSERT(!net->open); ++ net->do_ioctl = wl_cfgp2p_do_ioctl; ++ net->hard_start_xmit = wl_cfgp2p_start_xmit; ++ net->open = wl_cfgp2p_if_open; ++ net->stop = wl_cfgp2p_if_stop; ++#else ++ ASSERT(!net->netdev_ops); ++ net->netdev_ops = &wl_cfgp2p_if_ops; ++#endif ++ ++ /* Register with a dummy MAC addr */ ++ memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); ++ ++ wdev->wiphy = wl->wdev->wiphy; ++ ++ wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); ++ ++ net->ieee80211_ptr = wdev; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) ++ net->ethtool_ops = &cfgp2p_ethtool_ops; ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ ++ ++ SET_NETDEV_DEV(net, wiphy_dev(wdev->wiphy)); ++ ++ /* Associate p2p0 network interface with new wdev */ ++ wdev->netdev = net; ++ ++ ret = register_netdev(net); ++ if (ret) { ++ AP6211_ERR(" register_netdevice failed (%d)\n", ret); ++ free_netdev(net); ++ kfree(wdev); ++ return -ENODEV; ++ } ++ ++ /* store p2p net ptr for further reference. Note that iflist won't have this ++ * entry as there corresponding firmware interface is a "Hidden" interface. ++ */ ++ wl->p2p_wdev = wdev; ++ wl->p2p_net = net; ++ ++ AP6211_DEBUG("%s: P2P Interface Registered\n", net->name); ++ ++ return ret; ++} ++ ++s32 ++wl_cfgp2p_unregister_ndev(struct wl_priv *wl) ++{ ++ ++ if (!wl || !wl->p2p_net) { ++ AP6211_ERR("Invalid Ptr\n"); ++ return -EINVAL; ++ } ++ ++ unregister_netdev(wl->p2p_net); ++ free_netdev(wl->p2p_net); ++ ++ return 0; ++} ++static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev) ++{ ++ if (skb) ++ { ++ AP6211_DEBUG("(%s) is not used for data operations.Droping the packet.\n", ++ ndev->name); ++ dev_kfree_skb_any(skb); ++ } ++ ++ return 0; ++} ++ ++static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd) ++{ ++ int ret = 0; ++ struct wl_priv *wl = *(struct wl_priv **)netdev_priv(net); ++ struct net_device *ndev = wl_to_prmry_ndev(wl); ++ ++ /* There is no ifidx corresponding to p2p0 in our firmware. So we should ++ * not Handle any IOCTL cmds on p2p0 other than ANDROID PRIVATE CMDs. ++ * For Android PRIV CMD handling map it to primary I/F ++ */ ++ if (cmd == SIOCDEVPRIVATE+1) { ++ ret = wl_android_priv_cmd(ndev, ifr, cmd); ++ ++ } else { ++ AP6211_ERR("%s: IOCTL req 0x%x on p2p0 I/F. Ignoring. \n", ++ __FUNCTION__, cmd); ++ return -1; ++ } ++ ++ return ret; ++} ++ ++static int wl_cfgp2p_if_open(struct net_device *net) ++{ ++ extern struct wl_priv *wlcfg_drv_priv; ++ struct wireless_dev *wdev = net->ieee80211_ptr; ++ struct wl_priv *wl = NULL; ++ wl = wlcfg_drv_priv; ++ if (!wdev || !wl || !wl->p2p) ++ return -EINVAL; ++ AP6211_DEBUG("Enter\n"); ++ /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now, ++ * do it here. This will make sure that in concurrent mode, supplicant ++ * is not dependent on a particular order of interface initialization. ++ * i.e you may give wpa_supp -iwlan0 -N -ip2p0 or wpa_supp -ip2p0 -N ++ * -iwlan0. ++ */ ++ wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT) ++ | BIT(NL80211_IFTYPE_P2P_GO)); ++ wl_cfg80211_do_driver_init(net); ++ ++ return 0; ++} ++ ++static int wl_cfgp2p_if_stop(struct net_device *net) ++{ ++ extern struct wl_priv *wlcfg_drv_priv; ++ struct wl_priv *wl = NULL; ++ unsigned long flags; ++ struct wireless_dev *wdev = net->ieee80211_ptr; ++ int clear_flag = 0; ++ if (!wdev) ++ return -EINVAL; ++ ++ AP6211_DEBUG("Enter\n"); ++ wl = wlcfg_drv_priv; ++ if (!wl) ++ return -EINVAL; ++ spin_lock_irqsave(&wl->cfgdrv_lock, flags); ++ if (wl->scan_request && wl->scan_request->dev == net) { ++ cfg80211_scan_done(wl->scan_request, true); ++ wl->scan_request = NULL; ++ clear_flag = 1; ++ } ++ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); ++ if (clear_flag) ++ wl_clr_drv_status(wl, SCANNING, net); ++ wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes) ++ & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)| ++ BIT(NL80211_IFTYPE_P2P_GO))); ++ return 0; ++} ++ ++bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops) ++{ ++ return (if_ops == &wl_cfgp2p_if_ops); ++} +diff --git a/drivers/net/wireless/ap6211/wl_cfgp2p.h b/drivers/net/wireless/ap6211/wl_cfgp2p.h +new file mode 100755 +index 0000000..d3552d6 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_cfgp2p.h +@@ -0,0 +1,311 @@ ++/* ++ * Linux cfgp2p driver ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_cfgp2p.h 368091 2012-11-12 04:28:31Z $ ++ */ ++#ifndef _wl_cfgp2p_h_ ++#define _wl_cfgp2p_h_ ++#include ++#include ++ ++struct wl_priv; ++extern u32 wl_dbg_level; ++ ++typedef struct wifi_p2p_ie wifi_wfd_ie_t; ++/* Enumeration of the usages of the BSSCFGs used by the P2P Library. Do not ++ * confuse this with a bsscfg index. This value is an index into the ++ * saved_ie[] array of structures which in turn contains a bsscfg index field. ++ */ ++typedef enum { ++ P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */ ++ P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */ ++ P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */ ++ P2PAPI_BSSCFG_MAX ++} p2p_bsscfg_type_t; ++ ++/* vendor ies max buffer length for probe response or beacon */ ++#define VNDR_IES_MAX_BUF_LEN 1400 ++/* normal vendor ies buffer length */ ++#define VNDR_IES_BUF_LEN 512 ++ ++/* Structure to hold all saved P2P and WPS IEs for a BSSCFG */ ++struct p2p_saved_ie { ++ u8 p2p_probe_req_ie[VNDR_IES_BUF_LEN]; ++ u8 p2p_probe_res_ie[VNDR_IES_MAX_BUF_LEN]; ++ u8 p2p_assoc_req_ie[VNDR_IES_BUF_LEN]; ++ u8 p2p_assoc_res_ie[VNDR_IES_BUF_LEN]; ++ u8 p2p_beacon_ie[VNDR_IES_MAX_BUF_LEN]; ++ u32 p2p_probe_req_ie_len; ++ u32 p2p_probe_res_ie_len; ++ u32 p2p_assoc_req_ie_len; ++ u32 p2p_assoc_res_ie_len; ++ u32 p2p_beacon_ie_len; ++}; ++ ++struct p2p_bss { ++ u32 bssidx; ++ struct net_device *dev; ++ struct p2p_saved_ie saved_ie; ++ void *private_data; ++}; ++ ++struct p2p_info { ++ bool on; /* p2p on/off switch */ ++ bool scan; ++ bool vif_created; ++ s8 vir_ifname[IFNAMSIZ]; ++ unsigned long status; ++ struct ether_addr dev_addr; ++ struct ether_addr int_addr; ++ struct p2p_bss bss_idx[P2PAPI_BSSCFG_MAX]; ++ struct timer_list listen_timer; ++ wl_p2p_sched_t noa; ++ wl_p2p_ops_t ops; ++ wlc_ssid_t ssid; ++}; ++ ++#define MAX_VNDR_IE_NUMBER 5 ++ ++struct parsed_vndr_ie_info { ++ char *ie_ptr; ++ u32 ie_len; /* total length including id & length field */ ++ vndr_ie_t vndrie; ++}; ++ ++struct parsed_vndr_ies { ++ u32 count; ++ struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER]; ++}; ++ ++/* dongle status */ ++enum wl_cfgp2p_status { ++ WLP2P_STATUS_DISCOVERY_ON = 0, ++ WLP2P_STATUS_SEARCH_ENABLED, ++ WLP2P_STATUS_IF_ADD, ++ WLP2P_STATUS_IF_DEL, ++ WLP2P_STATUS_IF_DELETING, ++ WLP2P_STATUS_IF_CHANGING, ++ WLP2P_STATUS_IF_CHANGED, ++ WLP2P_STATUS_LISTEN_EXPIRED, ++ WLP2P_STATUS_ACTION_TX_COMPLETED, ++ WLP2P_STATUS_ACTION_TX_NOACK, ++ WLP2P_STATUS_SCANNING, ++ WLP2P_STATUS_GO_NEG_PHASE, ++ WLP2P_STATUS_DISC_IN_PROGRESS ++}; ++ ++ ++#define wl_to_p2p_bss_ndev(wl, type) ((wl)->p2p->bss_idx[type].dev) ++#define wl_to_p2p_bss_bssidx(wl, type) ((wl)->p2p->bss_idx[type].bssidx) ++#define wl_to_p2p_bss_saved_ie(wl, type) ((wl)->p2p->bss_idx[type].saved_ie) ++#define wl_to_p2p_bss_private(wl, type) ((wl)->p2p->bss_idx[type].private_data) ++#define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type]) ++#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : test_bit(WLP2P_STATUS_ ## stat, \ ++ &(wl)->p2p->status)) ++#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : set_bit(WLP2P_STATUS_ ## stat, \ ++ &(wl)->p2p->status)) ++#define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : clear_bit(WLP2P_STATUS_ ## stat, \ ++ &(wl)->p2p->status)) ++#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:change_bit(WLP2P_STATUS_ ## stat, \ ++ &(wl)->p2p->status)) ++#define p2p_on(wl) ((wl)->p2p->on) ++#define p2p_scan(wl) ((wl)->p2p->scan) ++#define p2p_is_on(wl) ((wl)->p2p && (wl)->p2p->on) ++ ++/* dword align allocation */ ++#define WLC_IOCTL_MAXLEN 8192 ++ ++#define INIT_TIMER(timer, func, duration, extra_delay) \ ++ do { \ ++ init_timer(timer); \ ++ timer->function = func; \ ++ timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \ ++ timer->data = (unsigned long) wl; \ ++ add_timer(timer); \ ++ } while (0); ++extern void ++wl_cfgp2p_listen_expired(unsigned long data); ++extern bool ++wl_cfgp2p_is_pub_action(void *frame, u32 frame_len); ++extern bool ++wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len); ++extern bool ++wl_cfgp2p_is_gas_action(void *frame, u32 frame_len); ++extern void ++wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len); ++extern s32 ++wl_cfgp2p_init_priv(struct wl_priv *wl); ++extern void ++wl_cfgp2p_deinit_priv(struct wl_priv *wl); ++extern s32 ++wl_cfgp2p_set_firm_p2p(struct wl_priv *wl); ++extern s32 ++wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, ++ u32 channel, u16 listen_ms, int bssidx); ++extern s32 ++wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, ++ chanspec_t chspec); ++extern s32 ++wl_cfgp2p_ifdisable(struct wl_priv *wl, struct ether_addr *mac); ++extern s32 ++wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac); ++extern s32 ++wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, chanspec_t chspec); ++ ++extern s32 ++wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index); ++ ++extern s32 ++wl_cfgp2p_init_discovery(struct wl_priv *wl); ++extern s32 ++wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, const u8 *ie, u32 ie_len); ++extern s32 ++wl_cfgp2p_disable_discovery(struct wl_priv *wl); ++extern s32 ++wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, u32 num_chans, ++ u16 *channels, ++ s32 search_state, u16 action, u32 bssidx); ++ ++extern s32 ++wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev, ++ s32 bssidx, s32 channel); ++ ++extern wpa_ie_fixed_t * ++wl_cfgp2p_find_wpaie(u8 *parse, u32 len); ++ ++extern wpa_ie_fixed_t * ++wl_cfgp2p_find_wpsie(u8 *parse, u32 len); ++ ++extern wifi_p2p_ie_t * ++wl_cfgp2p_find_p2pie(u8 *parse, u32 len); ++ ++extern wifi_wfd_ie_t * ++wl_cfgp2p_find_wfdie(u8 *parse, u32 len); ++extern s32 ++wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, ++ s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len); ++extern s32 ++wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx); ++ ++extern s32 ++wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev); ++extern struct net_device * ++wl_cfgp2p_find_ndev(struct wl_priv *wl, s32 bssidx); ++ ++ ++extern s32 ++wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++extern s32 ++wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms); ++ ++extern s32 ++wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 enable); ++ ++extern s32 ++wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, ++ const wl_event_msg_t *e, void *data); ++extern s32 ++wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, ++ wl_af_params_t *af_params, s32 bssidx); ++ ++extern void ++wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, struct ether_addr *out_dev_addr, ++ struct ether_addr *out_int_addr); ++ ++extern void ++wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id); ++extern bool ++wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx); ++ ++extern s32 ++wl_cfgp2p_bss(struct wl_priv *wl, struct net_device *ndev, s32 bsscfg_idx, s32 up); ++ ++ ++extern s32 ++wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev); ++ ++extern s32 ++wl_cfgp2p_down(struct wl_priv *wl); ++ ++extern s32 ++wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len); ++ ++extern s32 ++wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len); ++ ++extern s32 ++wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len); ++ ++extern u8 * ++wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id); ++ ++extern u8 * ++wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length); ++ ++extern s32 ++wl_cfgp2p_register_ndev(struct wl_priv *wl); ++ ++extern s32 ++wl_cfgp2p_unregister_ndev(struct wl_priv *wl); ++ ++extern bool ++wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops); ++ ++/* WiFi Direct */ ++#define SOCIAL_CHAN_1 1 ++#define SOCIAL_CHAN_2 6 ++#define SOCIAL_CHAN_3 11 ++#define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \ ++ (channel == SOCIAL_CHAN_2) || \ ++ (channel == SOCIAL_CHAN_3)) ++#define SOCIAL_CHAN_CNT 3 ++#define AF_PEER_SEARCH_CNT 2 ++#define WL_P2P_WILDCARD_SSID "DIRECT-" ++#define WL_P2P_WILDCARD_SSID_LEN 7 ++#define WL_P2P_INTERFACE_PREFIX "p2p" ++#define WL_P2P_TEMP_CHAN 11 ++ ++/* If the provision discovery is for JOIN operations, ++ * then we need not do an internal scan to find GO. ++ */ ++#define IS_PROV_DISC_WITHOUT_GROUP_ID(p2p_ie, len) \ ++ (wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_GROUP_ID) == NULL) ++ ++#define IS_GAS_REQ(frame, len) (wl_cfgp2p_is_gas_action(frame, len) && \ ++ ((frame->action == P2PSD_ACTION_ID_GAS_IREQ) || \ ++ (frame->action == P2PSD_ACTION_ID_GAS_CREQ))) ++#define IS_P2P_PUB_ACT_REQ(frame, p2p_ie, len) \ ++ (wl_cfgp2p_is_pub_action(frame, len) && \ ++ ((frame->subtype == P2P_PAF_GON_REQ) || \ ++ (frame->subtype == P2P_PAF_INVITE_REQ) || \ ++ ((frame->subtype == P2P_PAF_PROVDIS_REQ) && \ ++ IS_PROV_DISC_WITHOUT_GROUP_ID(p2p_ie, len)))) ++#define IS_P2P_PUB_ACT_RSP_SUBTYPE(subtype) ((subtype == P2P_PAF_GON_RSP) || \ ++ ((subtype == P2P_PAF_GON_CONF) || \ ++ (subtype == P2P_PAF_INVITE_RSP) || \ ++ (subtype == P2P_PAF_PROVDIS_RSP))) ++#define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3)) ++#define IS_P2P_SSID(ssid, len) (!memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) && \ ++ (len == WL_P2P_WILDCARD_SSID_LEN)) ++#endif /* _wl_cfgp2p_h_ */ +diff --git a/drivers/net/wireless/ap6211/wl_iw.c b/drivers/net/wireless/ap6211/wl_iw.c +new file mode 100755 +index 0000000..8e067f4 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_iw.c +@@ -0,0 +1,3622 @@ ++/* ++ * Linux Wireless Extensions support ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_iw.c 352251 2012-08-22 06:08:38Z $ ++ */ ++ ++#if defined(USE_IW) ++#define LINUX_PORT ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++ ++typedef const struct si_pub si_t; ++#include ++ ++ ++#include ++ ++#include ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++#include ++#endif ++#if defined(SOFTAP) ++struct net_device *ap_net_dev = NULL; ++tsk_ctl_t ap_eth_ctl; /* apsta AP netdev waiter thread */ ++#endif /* SOFTAP */ ++ ++extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status, ++ uint32 reason, char* stringBuf, uint buflen); ++ ++uint iw_msg_level = WL_ERROR_VAL; ++ ++#define MAX_WLIW_IOCTL_LEN 1024 ++ ++/* IOCTL swapping mode for Big Endian host with Little Endian dongle. Default to off */ ++#define htod32(i) i ++#define htod16(i) i ++#define dtoh32(i) i ++#define dtoh16(i) i ++#define htodchanspec(i) i ++#define dtohchanspec(i) i ++ ++extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); ++extern int dhd_wait_pend8021x(struct net_device *dev); ++ ++#if WIRELESS_EXT < 19 ++#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) ++#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST) ++#endif /* WIRELESS_EXT < 19 */ ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++#define DAEMONIZE(a) daemonize(a); \ ++ allow_signal(SIGKILL); \ ++ allow_signal(SIGTERM); ++#else /* Linux 2.4 (w/o preemption patch) */ ++#define RAISE_RX_SOFTIRQ() \ ++ cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) ++#define DAEMONIZE(a) daemonize(); \ ++ do { if (a) \ ++ strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \ ++ } while (0); ++#endif /* LINUX_VERSION_CODE */ ++ ++#define ISCAN_STATE_IDLE 0 ++#define ISCAN_STATE_SCANING 1 ++ ++/* the buf lengh can be WLC_IOCTL_MAXLEN (8K) to reduce iteration */ ++#define WLC_IW_ISCAN_MAXLEN 2048 ++typedef struct iscan_buf { ++ struct iscan_buf * next; ++ char iscan_buf[WLC_IW_ISCAN_MAXLEN]; ++} iscan_buf_t; ++ ++typedef struct iscan_info { ++ struct net_device *dev; ++ struct timer_list timer; ++ uint32 timer_ms; ++ uint32 timer_on; ++ int iscan_state; ++ iscan_buf_t * list_hdr; ++ iscan_buf_t * list_cur; ++ ++ /* Thread to work on iscan */ ++ long sysioc_pid; ++ struct semaphore sysioc_sem; ++ struct completion sysioc_exited; ++ ++ ++ char ioctlbuf[WLC_IOCTL_SMLEN]; ++} iscan_info_t; ++iscan_info_t *g_iscan = NULL; ++static void wl_iw_timerfunc(ulong data); ++static void wl_iw_set_event_mask(struct net_device *dev); ++static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action); ++ ++/* priv_link becomes netdev->priv and is the link between netdev and wlif struct */ ++typedef struct priv_link { ++ wl_iw_t *wliw; ++} priv_link_t; ++ ++/* dev to priv_link */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) ++#define WL_DEV_LINK(dev) (priv_link_t*)(dev->priv) ++#else ++#define WL_DEV_LINK(dev) (priv_link_t*)netdev_priv(dev) ++#endif ++ ++/* dev to wl_iw_t */ ++#define IW_DEV_IF(dev) ((wl_iw_t*)(WL_DEV_LINK(dev))->wliw) ++ ++static void swap_key_from_BE( ++ wl_wsec_key_t *key ++) ++{ ++ key->index = htod32(key->index); ++ key->len = htod32(key->len); ++ key->algo = htod32(key->algo); ++ key->flags = htod32(key->flags); ++ key->rxiv.hi = htod32(key->rxiv.hi); ++ key->rxiv.lo = htod16(key->rxiv.lo); ++ key->iv_initialized = htod32(key->iv_initialized); ++} ++ ++static void swap_key_to_BE( ++ wl_wsec_key_t *key ++) ++{ ++ key->index = dtoh32(key->index); ++ key->len = dtoh32(key->len); ++ key->algo = dtoh32(key->algo); ++ key->flags = dtoh32(key->flags); ++ key->rxiv.hi = dtoh32(key->rxiv.hi); ++ key->rxiv.lo = dtoh16(key->rxiv.lo); ++ key->iv_initialized = dtoh32(key->iv_initialized); ++} ++ ++static int ++dev_wlc_ioctl( ++ struct net_device *dev, ++ int cmd, ++ void *arg, ++ int len ++) ++{ ++ struct ifreq ifr; ++ wl_ioctl_t ioc; ++ mm_segment_t fs; ++ int ret; ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ioc.cmd = cmd; ++ ioc.buf = arg; ++ ioc.len = len; ++ ++ strcpy(ifr.ifr_name, dev->name); ++ ifr.ifr_data = (caddr_t) &ioc; ++ ++#ifndef LINUX_HYBRID ++ /* Causes an extraneous 'up'. If specific ioctls are failing due ++ to device down, then we can investigate those ioctls. ++ */ ++ dev_open(dev); ++#endif ++ ++ fs = get_fs(); ++ set_fs(get_ds()); ++#if defined(WL_USE_NETDEV_OPS) ++ ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); ++#else ++ ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); ++#endif ++ set_fs(fs); ++ ++ return ret; ++} ++ ++/* ++set named driver variable to int value and return error indication ++calling example: dev_wlc_intvar_set(dev, "arate", rate) ++*/ ++ ++static int ++dev_wlc_intvar_set( ++ struct net_device *dev, ++ char *name, ++ int val) ++{ ++ char buf[WLC_IOCTL_SMLEN]; ++ uint len; ++ ++ val = htod32(val); ++ len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf)); ++ ASSERT(len); ++ ++ return (dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len)); ++} ++ ++static int ++dev_iw_iovar_setbuf( ++ struct net_device *dev, ++ char *iovar, ++ void *param, ++ int paramlen, ++ void *bufptr, ++ int buflen) ++{ ++ int iolen; ++ ++ iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen); ++ ASSERT(iolen); ++ BCM_REFERENCE(iolen); ++ ++ return (dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen)); ++} ++ ++static int ++dev_iw_iovar_getbuf( ++ struct net_device *dev, ++ char *iovar, ++ void *param, ++ int paramlen, ++ void *bufptr, ++ int buflen) ++{ ++ int iolen; ++ ++ iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen); ++ ASSERT(iolen); ++ BCM_REFERENCE(iolen); ++ ++ return (dev_wlc_ioctl(dev, WLC_GET_VAR, bufptr, buflen)); ++} ++ ++#if WIRELESS_EXT > 17 ++static int ++dev_wlc_bufvar_set( ++ struct net_device *dev, ++ char *name, ++ char *buf, int len) ++{ ++ char *ioctlbuf; ++ uint buflen; ++ int error; ++ ++ ioctlbuf = kmalloc(MAX_WLIW_IOCTL_LEN, GFP_KERNEL); ++ if (!ioctlbuf) ++ return -ENOMEM; ++ ++ buflen = bcm_mkiovar(name, buf, len, ioctlbuf, MAX_WLIW_IOCTL_LEN); ++ ASSERT(buflen); ++ error = dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen); ++ ++ kfree(ioctlbuf); ++ return error; ++} ++#endif /* WIRELESS_EXT > 17 */ ++ ++/* ++get named driver variable to int value and return error indication ++calling example: dev_wlc_bufvar_get(dev, "arate", &rate) ++*/ ++ ++static int ++dev_wlc_bufvar_get( ++ struct net_device *dev, ++ char *name, ++ char *buf, int buflen) ++{ ++ char *ioctlbuf; ++ int error; ++ ++ uint len; ++ ++ ioctlbuf = kmalloc(MAX_WLIW_IOCTL_LEN, GFP_KERNEL); ++ if (!ioctlbuf) ++ return -ENOMEM; ++ len = bcm_mkiovar(name, NULL, 0, ioctlbuf, MAX_WLIW_IOCTL_LEN); ++ ASSERT(len); ++ BCM_REFERENCE(len); ++ error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf, MAX_WLIW_IOCTL_LEN); ++ if (!error) ++ bcopy(ioctlbuf, buf, buflen); ++ ++ kfree(ioctlbuf); ++ return (error); ++} ++ ++/* ++get named driver variable to int value and return error indication ++calling example: dev_wlc_intvar_get(dev, "arate", &rate) ++*/ ++ ++static int ++dev_wlc_intvar_get( ++ struct net_device *dev, ++ char *name, ++ int *retval) ++{ ++ union { ++ char buf[WLC_IOCTL_SMLEN]; ++ int val; ++ } var; ++ int error; ++ ++ uint len; ++ uint data_null; ++ ++ len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf)); ++ ASSERT(len); ++ error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len); ++ ++ *retval = dtoh32(var.val); ++ ++ return (error); ++} ++ ++/* Maintain backward compatibility */ ++#if WIRELESS_EXT < 13 ++struct iw_request_info ++{ ++ __u16 cmd; /* Wireless Extension command */ ++ __u16 flags; /* More to come ;-) */ ++}; ++ ++typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, ++ void *wrqu, char *extra); ++#endif /* WIRELESS_EXT < 13 */ ++ ++#if WIRELESS_EXT > 12 ++static int ++wl_iw_set_leddc( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra ++) ++{ ++ int dc = *(int *)extra; ++ int error; ++ ++ error = dev_wlc_intvar_set(dev, "leddc", dc); ++ return error; ++} ++ ++static int ++wl_iw_set_vlanmode( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra ++) ++{ ++ int mode = *(int *)extra; ++ int error; ++ ++ mode = htod32(mode); ++ error = dev_wlc_intvar_set(dev, "vlan_mode", mode); ++ return error; ++} ++ ++static int ++wl_iw_set_pm( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra ++) ++{ ++ int pm = *(int *)extra; ++ int error; ++ ++ pm = htod32(pm); ++ error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); ++ return error; ++} ++#endif /* WIRELESS_EXT > 12 */ ++ ++int ++wl_iw_send_priv_event( ++ struct net_device *dev, ++ char *flag ++) ++{ ++ union iwreq_data wrqu; ++ char extra[IW_CUSTOM_MAX + 1]; ++ int cmd; ++ ++ cmd = IWEVCUSTOM; ++ memset(&wrqu, 0, sizeof(wrqu)); ++ if (strlen(flag) > sizeof(extra)) ++ return -1; ++ ++ strcpy(extra, flag); ++ wrqu.data.length = strlen(extra); ++ wireless_send_event(dev, cmd, &wrqu, extra); ++ AP6211_DEBUG("Send IWEVCUSTOM Event as %s\n", extra); ++ ++ return 0; ++} ++ ++static int ++wl_iw_config_commit( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ void *zwrq, ++ char *extra ++) ++{ ++ wlc_ssid_t ssid; ++ int error; ++ struct sockaddr bssid; ++ ++ AP6211_DEBUG("%s: SIOCSIWCOMMIT\n", dev->name); ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) ++ return error; ++ ++ ssid.SSID_len = dtoh32(ssid.SSID_len); ++ ++ if (!ssid.SSID_len) ++ return 0; ++ ++ bzero(&bssid, sizeof(struct sockaddr)); ++ if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN))) { ++ AP6211_ERR("%s: WLC_REASSOC failed (%d)\n", __FUNCTION__, error); ++ return error; ++ } ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_name( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *cwrq, ++ char *extra ++) ++{ ++ int phytype, err; ++ uint band[3]; ++ char cap[5]; ++ ++ AP6211_DEBUG("%s: SIOCGIWNAME\n", dev->name); ++ ++ cap[0] = 0; ++ if ((err = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype))) < 0) ++ goto done; ++ if ((err = dev_wlc_ioctl(dev, WLC_GET_BANDLIST, band, sizeof(band))) < 0) ++ goto done; ++ ++ band[0] = dtoh32(band[0]); ++ switch (phytype) { ++ case WLC_PHY_TYPE_A: ++ strcpy(cap, "a"); ++ break; ++ case WLC_PHY_TYPE_B: ++ strcpy(cap, "b"); ++ break; ++ case WLC_PHY_TYPE_LP: ++ case WLC_PHY_TYPE_G: ++ if (band[0] >= 2) ++ strcpy(cap, "abg"); ++ else ++ strcpy(cap, "bg"); ++ break; ++ case WLC_PHY_TYPE_N: ++ if (band[0] >= 2) ++ strcpy(cap, "abgn"); ++ else ++ strcpy(cap, "bgn"); ++ break; ++ } ++done: ++ snprintf(cwrq->name, IFNAMSIZ, "IEEE 802.11%s", cap); ++ return 0; ++} ++ ++static int ++wl_iw_set_freq( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_freq *fwrq, ++ char *extra ++) ++{ ++ int error, chan; ++ uint sf = 0; ++ ++ AP6211_DEBUG("%s: SIOCSIWFREQ\n", dev->name); ++ ++ /* Setting by channel number */ ++ if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) { ++ chan = fwrq->m; ++ } ++ ++ /* Setting by frequency */ ++ else { ++ /* Convert to MHz as best we can */ ++ if (fwrq->e >= 6) { ++ fwrq->e -= 6; ++ while (fwrq->e--) ++ fwrq->m *= 10; ++ } else if (fwrq->e < 6) { ++ while (fwrq->e++ < 6) ++ fwrq->m /= 10; ++ } ++ /* handle 4.9GHz frequencies as Japan 4 GHz based channelization */ ++ if (fwrq->m > 4000 && fwrq->m < 5000) ++ sf = WF_CHAN_FACTOR_4_G; /* start factor for 4 GHz */ ++ ++ chan = wf_mhz2channel(fwrq->m, sf); ++ } ++ chan = htod32(chan); ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan)))) ++ return error; ++ ++ /* -EINPROGRESS: Call commit handler */ ++ return -EINPROGRESS; ++} ++ ++static int ++wl_iw_get_freq( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_freq *fwrq, ++ char *extra ++) ++{ ++ channel_info_t ci; ++ int error; ++ ++ AP6211_DEBUG("%s: SIOCGIWFREQ\n", dev->name); ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) ++ return error; ++ ++ /* Return radio channel in channel form */ ++ fwrq->m = dtoh32(ci.hw_channel); ++ fwrq->e = dtoh32(0); ++ return 0; ++} ++ ++static int ++wl_iw_set_mode( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ __u32 *uwrq, ++ char *extra ++) ++{ ++ int infra = 0, ap = 0, error = 0; ++ ++ AP6211_DEBUG("%s: SIOCSIWMODE\n", dev->name); ++ ++ switch (*uwrq) { ++ case IW_MODE_MASTER: ++ infra = ap = 1; ++ break; ++ case IW_MODE_ADHOC: ++ case IW_MODE_AUTO: ++ break; ++ case IW_MODE_INFRA: ++ infra = 1; ++ break; ++ default: ++ return -EINVAL; ++ } ++ infra = htod32(infra); ++ ap = htod32(ap); ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra))) || ++ (error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap)))) ++ return error; ++ ++ /* -EINPROGRESS: Call commit handler */ ++ return -EINPROGRESS; ++} ++ ++static int ++wl_iw_get_mode( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ __u32 *uwrq, ++ char *extra ++) ++{ ++ int error, infra = 0, ap = 0; ++ ++ AP6211_DEBUG("%s: SIOCGIWMODE\n", dev->name); ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra))) || ++ (error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap)))) ++ return error; ++ ++ infra = dtoh32(infra); ++ ap = dtoh32(ap); ++ *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC; ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_range( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ struct iw_range *range = (struct iw_range *) extra; ++ static int channels[MAXCHANNEL+1]; ++ wl_uint32_list_t *list = (wl_uint32_list_t *) channels; ++ wl_rateset_t rateset; ++ int error, i, k; ++ uint sf, ch; ++ ++ int phytype; ++ int bw_cap = 0, sgi_tx = 0, nmode = 0; ++ channel_info_t ci; ++ uint8 nrate_list2copy = 0; ++ uint16 nrate_list[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130}, ++ {14, 29, 43, 58, 87, 116, 130, 144}, ++ {27, 54, 81, 108, 162, 216, 243, 270}, ++ {30, 60, 90, 120, 180, 240, 270, 300}}; ++ ++ AP6211_DEBUG("%s: SIOCGIWRANGE\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ dwrq->length = sizeof(struct iw_range); ++ memset(range, 0, sizeof(*range)); ++ ++ /* We don't use nwids */ ++ range->min_nwid = range->max_nwid = 0; ++ ++ /* Set available channels/frequencies */ ++ list->count = htod32(MAXCHANNEL); ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, sizeof(channels)))) ++ return error; ++ for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) { ++ range->freq[i].i = dtoh32(list->element[i]); ++ ++ ch = dtoh32(list->element[i]); ++ if (ch <= CH_MAX_2G_CHANNEL) ++ sf = WF_CHAN_FACTOR_2_4_G; ++ else ++ sf = WF_CHAN_FACTOR_5_G; ++ ++ range->freq[i].m = wf_channel2mhz(ch, sf); ++ range->freq[i].e = 6; ++ } ++ range->num_frequency = range->num_channels = i; ++ ++ /* Link quality (use NDIS cutoffs) */ ++ range->max_qual.qual = 5; ++ /* Signal level (use RSSI) */ ++ range->max_qual.level = 0x100 - 200; /* -200 dBm */ ++ /* Noise level (use noise) */ ++ range->max_qual.noise = 0x100 - 200; /* -200 dBm */ ++ /* Signal level threshold range (?) */ ++ range->sensitivity = 65535; ++ ++#if WIRELESS_EXT > 11 ++ /* Link quality (use NDIS cutoffs) */ ++ range->avg_qual.qual = 3; ++ /* Signal level (use RSSI) */ ++ range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD; ++ /* Noise level (use noise) */ ++ range->avg_qual.noise = 0x100 - 75; /* -75 dBm */ ++#endif /* WIRELESS_EXT > 11 */ ++ ++ /* Set available bitrates */ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) ++ return error; ++ rateset.count = dtoh32(rateset.count); ++ range->num_bitrates = rateset.count; ++ for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++) ++ range->bitrate[i] = (rateset.rates[i] & 0x7f) * 500000; /* convert to bps */ ++ dev_wlc_intvar_get(dev, "nmode", &nmode); ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)))) ++ return error; ++ ++ if (nmode == 1 && ((phytype == WLC_PHY_TYPE_SSN) || (phytype == WLC_PHY_TYPE_LCN) || ++ (phytype == WLC_PHY_TYPE_LCN40))) { ++ dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap); ++ dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx); ++ dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t)); ++ ci.hw_channel = dtoh32(ci.hw_channel); ++ ++ if (bw_cap == 0 || ++ (bw_cap == 2 && ci.hw_channel <= 14)) { ++ if (sgi_tx == 0) ++ nrate_list2copy = 0; ++ else ++ nrate_list2copy = 1; ++ } ++ if (bw_cap == 1 || ++ (bw_cap == 2 && ci.hw_channel >= 36)) { ++ if (sgi_tx == 0) ++ nrate_list2copy = 2; ++ else ++ nrate_list2copy = 3; ++ } ++ range->num_bitrates += 8; ++ for (k = 0; i < range->num_bitrates; k++, i++) { ++ /* convert to bps */ ++ range->bitrate[i] = (nrate_list[nrate_list2copy][k]) * 500000; ++ } ++ } ++ ++ /* Set an indication of the max TCP throughput ++ * in bit/s that we can expect using this interface. ++ * May be use for QoS stuff... Jean II ++ */ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) ++ return error; ++ i = dtoh32(i); ++ if (i == WLC_PHY_TYPE_A) ++ range->throughput = 24000000; /* 24 Mbits/s */ ++ else ++ range->throughput = 1500000; /* 1.5 Mbits/s */ ++ ++ /* RTS and fragmentation thresholds */ ++ range->min_rts = 0; ++ range->max_rts = 2347; ++ range->min_frag = 256; ++ range->max_frag = 2346; ++ ++ range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS; ++ range->num_encoding_sizes = 4; ++ range->encoding_size[0] = WEP1_KEY_SIZE; ++ range->encoding_size[1] = WEP128_KEY_SIZE; ++#if WIRELESS_EXT > 17 ++ range->encoding_size[2] = TKIP_KEY_SIZE; ++#else ++ range->encoding_size[2] = 0; ++#endif ++ range->encoding_size[3] = AES_KEY_SIZE; ++ ++ /* Do not support power micro-management */ ++ range->min_pmp = 0; ++ range->max_pmp = 0; ++ range->min_pmt = 0; ++ range->max_pmt = 0; ++ range->pmp_flags = 0; ++ range->pm_capa = 0; ++ ++ /* Transmit Power - values are in mW */ ++ range->num_txpower = 2; ++ range->txpower[0] = 1; ++ range->txpower[1] = 255; ++ range->txpower_capa = IW_TXPOW_MWATT; ++ ++#if WIRELESS_EXT > 10 ++ range->we_version_compiled = WIRELESS_EXT; ++ range->we_version_source = 19; ++ ++ /* Only support retry limits */ ++ range->retry_capa = IW_RETRY_LIMIT; ++ range->retry_flags = IW_RETRY_LIMIT; ++ range->r_time_flags = 0; ++ /* SRL and LRL limits */ ++ range->min_retry = 1; ++ range->max_retry = 255; ++ /* Retry lifetime limits unsupported */ ++ range->min_r_time = 0; ++ range->max_r_time = 0; ++#endif /* WIRELESS_EXT > 10 */ ++ ++#if WIRELESS_EXT > 17 ++ range->enc_capa = IW_ENC_CAPA_WPA; ++ range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP; ++ range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP; ++ range->enc_capa |= IW_ENC_CAPA_WPA2; ++#if (defined(BCMSUP_PSK) && defined(WLFBT)) ++ /* Tell the host (e.g. wpa_supplicant) to let us do the handshake */ ++ range->enc_capa |= IW_ENC_CAPA_4WAY_HANDSHAKE; ++#endif /* (defined (BCMSUP_PSK) && defined(WLFBT)) */ ++ ++ /* Event capability (kernel) */ ++ IW_EVENT_CAPA_SET_KERNEL(range->event_capa); ++ /* Event capability (driver) */ ++ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); ++ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); ++ IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); ++ IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE); ++ IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCREQIE); ++ IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCRESPIE); ++ IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND); ++ ++#if WIRELESS_EXT >= 22 && defined(IW_SCAN_CAPA_ESSID) ++ /* FC7 wireless.h defines EXT 22 but doesn't define scan_capa bits */ ++ range->scan_capa = IW_SCAN_CAPA_ESSID; ++#endif ++#endif /* WIRELESS_EXT > 17 */ ++ ++ return 0; ++} ++ ++static int ++rssi_to_qual(int rssi) ++{ ++ if (rssi <= WL_IW_RSSI_NO_SIGNAL) ++ return 0; ++ else if (rssi <= WL_IW_RSSI_VERY_LOW) ++ return 1; ++ else if (rssi <= WL_IW_RSSI_LOW) ++ return 2; ++ else if (rssi <= WL_IW_RSSI_GOOD) ++ return 3; ++ else if (rssi <= WL_IW_RSSI_VERY_GOOD) ++ return 4; ++ else ++ return 5; ++} ++ ++static int ++wl_iw_set_spy( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_iw_t *iw = IW_DEV_IF(dev); ++ struct sockaddr *addr = (struct sockaddr *) extra; ++ int i; ++ ++ AP6211_DEBUG("%s: SIOCSIWSPY\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ iw->spy_num = MIN(ARRAYSIZE(iw->spy_addr), dwrq->length); ++ for (i = 0; i < iw->spy_num; i++) ++ memcpy(&iw->spy_addr[i], addr[i].sa_data, ETHER_ADDR_LEN); ++ memset(iw->spy_qual, 0, sizeof(iw->spy_qual)); ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_spy( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_iw_t *iw = IW_DEV_IF(dev); ++ struct sockaddr *addr = (struct sockaddr *) extra; ++ struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num]; ++ int i; ++ ++ AP6211_DEBUG("%s: SIOCGIWSPY\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ dwrq->length = iw->spy_num; ++ for (i = 0; i < iw->spy_num; i++) { ++ memcpy(addr[i].sa_data, &iw->spy_addr[i], ETHER_ADDR_LEN); ++ addr[i].sa_family = AF_UNIX; ++ memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality)); ++ iw->spy_qual[i].updated = 0; ++ } ++ ++ return 0; ++} ++ ++static int ++wl_iw_set_wap( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *awrq, ++ char *extra ++) ++{ ++ int error = -EINVAL; ++ ++ AP6211_DEBUG("%s: SIOCSIWAP\n", dev->name); ++ ++ if (awrq->sa_family != ARPHRD_ETHER) { ++ AP6211_ERR("%s: Invalid Header...sa_family\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ /* Ignore "auto" or "off" */ ++ if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) { ++ scb_val_t scbval; ++ bzero(&scbval, sizeof(scb_val_t)); ++ if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)))) { ++ AP6211_ERR("%s: WLC_DISASSOC failed (%d).\n", __FUNCTION__, error); ++ } ++ return 0; ++ } ++ /* WL_ASSOC(("Assoc to %s\n", bcm_ether_ntoa((struct ether_addr *)&(awrq->sa_data), ++ * eabuf))); ++ */ ++ /* Reassociate to the specified AP */ ++ if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, awrq->sa_data, ETHER_ADDR_LEN))) { ++ AP6211_ERR("%s: WLC_REASSOC failed (%d).\n", __FUNCTION__, error); ++ return error; ++ } ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_wap( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *awrq, ++ char *extra ++) ++{ ++ AP6211_DEBUG("%s: SIOCGIWAP\n", dev->name); ++ ++ awrq->sa_family = ARPHRD_ETHER; ++ memset(awrq->sa_data, 0, ETHER_ADDR_LEN); ++ ++ /* Ignore error (may be down or disassociated) */ ++ (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN); ++ ++ return 0; ++} ++ ++#if WIRELESS_EXT > 17 ++static int ++wl_iw_mlme( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *awrq, ++ char *extra ++) ++{ ++ struct iw_mlme *mlme; ++ scb_val_t scbval; ++ int error = -EINVAL; ++ ++ AP6211_DEBUG("%s: SIOCSIWMLME\n", dev->name); ++ ++ mlme = (struct iw_mlme *)extra; ++ if (mlme == NULL) { ++ AP6211_ERR("Invalid ioctl data.\n"); ++ return error; ++ } ++ ++ scbval.val = mlme->reason_code; ++ bcopy(&mlme->addr.sa_data, &scbval.ea, ETHER_ADDR_LEN); ++ ++ if (mlme->cmd == IW_MLME_DISASSOC) { ++ scbval.val = htod32(scbval.val); ++ error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); ++ } ++ else if (mlme->cmd == IW_MLME_DEAUTH) { ++ scbval.val = htod32(scbval.val); ++ error = dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, ++ sizeof(scb_val_t)); ++ } ++ else { ++ AP6211_ERR("%s: Invalid ioctl data.\n", __FUNCTION__); ++ return error; ++ } ++ ++ return error; ++} ++#endif /* WIRELESS_EXT > 17 */ ++ ++static int ++wl_iw_get_aplist( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_scan_results_t *list; ++ struct sockaddr *addr = (struct sockaddr *) extra; ++ struct iw_quality qual[IW_MAX_AP]; ++ wl_bss_info_t *bi = NULL; ++ int error, i; ++ uint buflen = dwrq->length; ++ ++ AP6211_DEBUG("%s: SIOCGIWAPLIST\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ /* Get scan results (too large to put on the stack) */ ++ list = kmalloc(buflen, GFP_KERNEL); ++ if (!list) ++ return -ENOMEM; ++ memset(list, 0, buflen); ++ list->buflen = htod32(buflen); ++ if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) { ++ AP6211_ERR("%d: Scan results error %d\n", __LINE__, error); ++ kfree(list); ++ return error; ++ } ++ list->buflen = dtoh32(list->buflen); ++ list->version = dtoh32(list->version); ++ list->count = dtoh32(list->count); ++ ASSERT(list->version == WL_BSS_INFO_VERSION); ++ ++ for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { ++ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; ++ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + ++ buflen)); ++ ++ /* Infrastructure only */ ++ if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) ++ continue; ++ ++ /* BSSID */ ++ memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); ++ addr[dwrq->length].sa_family = ARPHRD_ETHER; ++ qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); ++ qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI); ++ qual[dwrq->length].noise = 0x100 + bi->phy_noise; ++ ++ /* Updated qual, level, and noise */ ++#if WIRELESS_EXT > 18 ++ qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; ++#else ++ qual[dwrq->length].updated = 7; ++#endif /* WIRELESS_EXT > 18 */ ++ ++ dwrq->length++; ++ } ++ ++ kfree(list); ++ ++ if (dwrq->length) { ++ memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length); ++ /* Provided qual */ ++ dwrq->flags = 1; ++ } ++ ++ return 0; ++} ++ ++static int ++wl_iw_iscan_get_aplist( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_scan_results_t *list; ++ iscan_buf_t * buf; ++ iscan_info_t *iscan = g_iscan; ++ ++ struct sockaddr *addr = (struct sockaddr *) extra; ++ struct iw_quality qual[IW_MAX_AP]; ++ wl_bss_info_t *bi = NULL; ++ int i; ++ ++ AP6211_DEBUG("%s: SIOCGIWAPLIST\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ if ((!iscan) || (iscan->sysioc_pid < 0)) { ++ return wl_iw_get_aplist(dev, info, dwrq, extra); ++ } ++ ++ buf = iscan->list_hdr; ++ /* Get scan results (too large to put on the stack) */ ++ while (buf) { ++ list = &((wl_iscan_results_t*)buf->iscan_buf)->results; ++ ASSERT(list->version == WL_BSS_INFO_VERSION); ++ ++ bi = NULL; ++ for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { ++ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; ++ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + ++ WLC_IW_ISCAN_MAXLEN)); ++ ++ /* Infrastructure only */ ++ if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) ++ continue; ++ ++ /* BSSID */ ++ memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); ++ addr[dwrq->length].sa_family = ARPHRD_ETHER; ++ qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); ++ qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI); ++ qual[dwrq->length].noise = 0x100 + bi->phy_noise; ++ ++ /* Updated qual, level, and noise */ ++#if WIRELESS_EXT > 18 ++ qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; ++#else ++ qual[dwrq->length].updated = 7; ++#endif /* WIRELESS_EXT > 18 */ ++ ++ dwrq->length++; ++ } ++ buf = buf->next; ++ } ++ if (dwrq->length) { ++ memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length); ++ /* Provided qual */ ++ dwrq->flags = 1; ++ } ++ ++ return 0; ++} ++ ++#if WIRELESS_EXT > 13 ++static int ++wl_iw_set_scan( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra ++) ++{ ++ wlc_ssid_t ssid; ++ ++ AP6211_DEBUG("%s: SIOCSIWSCAN\n", dev->name); ++ ++ /* default Broadcast scan */ ++ memset(&ssid, 0, sizeof(ssid)); ++ ++#if WIRELESS_EXT > 17 ++ /* check for given essid */ ++ if (wrqu->data.length == sizeof(struct iw_scan_req)) { ++ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { ++ struct iw_scan_req *req = (struct iw_scan_req *)extra; ++ ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len); ++ memcpy(ssid.SSID, req->essid, ssid.SSID_len); ++ ssid.SSID_len = htod32(ssid.SSID_len); ++ } ++ } ++#endif ++ /* Ignore error (most likely scan in progress) */ ++ (void) dev_wlc_ioctl(dev, WLC_SCAN, &ssid, sizeof(ssid)); ++ ++ return 0; ++} ++ ++static int ++wl_iw_iscan_set_scan( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra ++) ++{ ++ wlc_ssid_t ssid; ++ iscan_info_t *iscan = g_iscan; ++ ++ AP6211_DEBUG("%s: SIOCSIWSCAN\n", dev->name); ++ ++ /* use backup if our thread is not successful */ ++ if ((!iscan) || (iscan->sysioc_pid < 0)) { ++ return wl_iw_set_scan(dev, info, wrqu, extra); ++ } ++ if (iscan->iscan_state == ISCAN_STATE_SCANING) { ++ return 0; ++ } ++ ++ /* default Broadcast scan */ ++ memset(&ssid, 0, sizeof(ssid)); ++ ++#if WIRELESS_EXT > 17 ++ /* check for given essid */ ++ if (wrqu->data.length == sizeof(struct iw_scan_req)) { ++ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { ++ struct iw_scan_req *req = (struct iw_scan_req *)extra; ++ ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len); ++ memcpy(ssid.SSID, req->essid, ssid.SSID_len); ++ ssid.SSID_len = htod32(ssid.SSID_len); ++ } ++ } ++#endif ++ ++ iscan->list_cur = iscan->list_hdr; ++ iscan->iscan_state = ISCAN_STATE_SCANING; ++ ++ ++ wl_iw_set_event_mask(dev); ++ wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START); ++ ++ iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms); ++ add_timer(&iscan->timer); ++ iscan->timer_on = 1; ++ ++ return 0; ++} ++ ++#if WIRELESS_EXT > 17 ++static bool ++ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len) ++{ ++/* Is this body of this tlvs entry a WPA entry? If */ ++/* not update the tlvs buffer pointer/length */ ++ uint8 *ie = *wpaie; ++ ++ /* If the contents match the WPA_OUI and type=1 */ ++ if ((ie[1] >= 6) && ++ !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) { ++ return TRUE; ++ } ++ ++ /* point to the next ie */ ++ ie += ie[1] + 2; ++ /* calculate the length of the rest of the buffer */ ++ *tlvs_len -= (int)(ie - *tlvs); ++ /* update the pointer to the start of the buffer */ ++ *tlvs = ie; ++ return FALSE; ++} ++ ++static bool ++ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len) ++{ ++/* Is this body of this tlvs entry a WPS entry? If */ ++/* not update the tlvs buffer pointer/length */ ++ uint8 *ie = *wpsie; ++ ++ /* If the contents match the WPA_OUI and type=4 */ ++ if ((ie[1] >= 4) && ++ !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) { ++ return TRUE; ++ } ++ ++ /* point to the next ie */ ++ ie += ie[1] + 2; ++ /* calculate the length of the rest of the buffer */ ++ *tlvs_len -= (int)(ie - *tlvs); ++ /* update the pointer to the start of the buffer */ ++ *tlvs = ie; ++ return FALSE; ++} ++#endif /* WIRELESS_EXT > 17 */ ++ ++ ++static int ++wl_iw_handle_scanresults_ies(char **event_p, char *end, ++ struct iw_request_info *info, wl_bss_info_t *bi) ++{ ++#if WIRELESS_EXT > 17 ++ struct iw_event iwe; ++ char *event; ++ ++ event = *event_p; ++ if (bi->ie_length) { ++ /* look for wpa/rsn ies in the ie list... */ ++ bcm_tlv_t *ie; ++ uint8 *ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); ++ int ptr_len = bi->ie_length; ++ ++ if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID))) { ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = ie->len + 2; ++ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); ++ } ++ ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); ++ ++#if defined(WLFBT) ++ if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_MDIE_ID))) { ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = ie->len + 2; ++ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); ++ } ++ ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); ++#endif /* WLFBT */ ++ ++ while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) { ++ /* look for WPS IE */ ++ if (ie_is_wps_ie(((uint8 **)&ie), &ptr, &ptr_len)) { ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = ie->len + 2; ++ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); ++ break; ++ } ++ } ++ ++ ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); ++ ptr_len = bi->ie_length; ++ while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) { ++ if (ie_is_wpa_ie(((uint8 **)&ie), &ptr, &ptr_len)) { ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = ie->len + 2; ++ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); ++ break; ++ } ++ } ++ ++ *event_p = event; ++ } ++ ++#endif /* WIRELESS_EXT > 17 */ ++ return 0; ++} ++static int ++wl_iw_get_scan( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ channel_info_t ci; ++ wl_scan_results_t *list; ++ struct iw_event iwe; ++ wl_bss_info_t *bi = NULL; ++ int error, i, j; ++ char *event = extra, *end = extra + dwrq->length, *value; ++ uint buflen = dwrq->length; ++ ++ AP6211_DEBUG("%s: SIOCGIWSCAN\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ /* Check for scan in progress */ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) ++ return error; ++ ci.scan_channel = dtoh32(ci.scan_channel); ++ if (ci.scan_channel) ++ return -EAGAIN; ++ ++ /* Get scan results (too large to put on the stack) */ ++ list = kmalloc(buflen, GFP_KERNEL); ++ if (!list) ++ return -ENOMEM; ++ memset(list, 0, buflen); ++ list->buflen = htod32(buflen); ++ if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) { ++ kfree(list); ++ return error; ++ } ++ list->buflen = dtoh32(list->buflen); ++ list->version = dtoh32(list->version); ++ list->count = dtoh32(list->count); ++ ++ ASSERT(list->version == WL_BSS_INFO_VERSION); ++ ++ for (i = 0; i < list->count && i < IW_MAX_AP; i++) { ++ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; ++ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + ++ buflen)); ++ ++ /* First entry must be the BSSID */ ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); ++ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); ++ ++ /* SSID */ ++ iwe.u.data.length = dtoh32(bi->SSID_len); ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.flags = 1; ++ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); ++ ++ /* Mode */ ++ if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { ++ iwe.cmd = SIOCGIWMODE; ++ if (dtoh16(bi->capability) & DOT11_CAP_ESS) ++ iwe.u.mode = IW_MODE_INFRA; ++ else ++ iwe.u.mode = IW_MODE_ADHOC; ++ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); ++ } ++ ++ /* Channel */ ++ iwe.cmd = SIOCGIWFREQ; ++ iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec), ++ CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ? ++ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); ++ iwe.u.freq.e = 6; ++ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); ++ ++ /* Channel quality */ ++ iwe.cmd = IWEVQUAL; ++ iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); ++ iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); ++ iwe.u.qual.noise = 0x100 + bi->phy_noise; ++ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); ++ ++ /* WPA, WPA2, WPS, WAPI IEs */ ++ wl_iw_handle_scanresults_ies(&event, end, info, bi); ++ ++ /* Encryption */ ++ iwe.cmd = SIOCGIWENCODE; ++ if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) ++ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ iwe.u.data.length = 0; ++ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); ++ ++ /* Rates */ ++ if (bi->rateset.count) { ++ value = event + IW_EV_LCP_LEN; ++ iwe.cmd = SIOCGIWRATE; ++ /* Those two flags are ignored... */ ++ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; ++ for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) { ++ iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000; ++ value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe, ++ IW_EV_PARAM_LEN); ++ } ++ event = value; ++ } ++ } ++ ++ kfree(list); ++ ++ dwrq->length = event - extra; ++ dwrq->flags = 0; /* todo */ ++ ++ return 0; ++} ++ ++static int ++wl_iw_iscan_get_scan( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_scan_results_t *list; ++ struct iw_event iwe; ++ wl_bss_info_t *bi = NULL; ++ int ii, j; ++ int apcnt; ++ char *event = extra, *end = extra + dwrq->length, *value; ++ iscan_info_t *iscan = g_iscan; ++ iscan_buf_t * p_buf; ++ ++ AP6211_DEBUG("%s: SIOCGIWSCAN\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ /* use backup if our thread is not successful */ ++ if ((!iscan) || (iscan->sysioc_pid < 0)) { ++ return wl_iw_get_scan(dev, info, dwrq, extra); ++ } ++ ++ /* Check for scan in progress */ ++ if (iscan->iscan_state == ISCAN_STATE_SCANING) ++ return -EAGAIN; ++ ++ apcnt = 0; ++ p_buf = iscan->list_hdr; ++ /* Get scan results */ ++ while (p_buf != iscan->list_cur) { ++ list = &((wl_iscan_results_t*)p_buf->iscan_buf)->results; ++ ++ if (list->version != WL_BSS_INFO_VERSION) { ++ AP6211_ERR("list->version %d != WL_BSS_INFO_VERSION\n", list->version); ++ } ++ ++ bi = NULL; ++ for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) { ++ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; ++ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + ++ WLC_IW_ISCAN_MAXLEN)); ++ ++ /* overflow check cover fields before wpa IEs */ ++ if (event + ETHER_ADDR_LEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN + ++ IW_EV_QUAL_LEN >= end) ++ return -E2BIG; ++ /* First entry must be the BSSID */ ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); ++ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); ++ ++ /* SSID */ ++ iwe.u.data.length = dtoh32(bi->SSID_len); ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.flags = 1; ++ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); ++ ++ /* Mode */ ++ if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { ++ iwe.cmd = SIOCGIWMODE; ++ if (dtoh16(bi->capability) & DOT11_CAP_ESS) ++ iwe.u.mode = IW_MODE_INFRA; ++ else ++ iwe.u.mode = IW_MODE_ADHOC; ++ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); ++ } ++ ++ /* Channel */ ++ iwe.cmd = SIOCGIWFREQ; ++ iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec), ++ CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ? ++ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); ++ iwe.u.freq.e = 6; ++ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); ++ ++ /* Channel quality */ ++ iwe.cmd = IWEVQUAL; ++ iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); ++ iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); ++ iwe.u.qual.noise = 0x100 + bi->phy_noise; ++ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); ++ ++ /* WPA, WPA2, WPS, WAPI IEs */ ++ wl_iw_handle_scanresults_ies(&event, end, info, bi); ++ ++ /* Encryption */ ++ iwe.cmd = SIOCGIWENCODE; ++ if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) ++ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ iwe.u.data.length = 0; ++ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); ++ ++ /* Rates */ ++ if (bi->rateset.count <= sizeof(bi->rateset.rates)) { ++ if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end) ++ return -E2BIG; ++ ++ value = event + IW_EV_LCP_LEN; ++ iwe.cmd = SIOCGIWRATE; ++ /* Those two flags are ignored... */ ++ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; ++ for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) { ++ iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000; ++ value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe, ++ IW_EV_PARAM_LEN); ++ } ++ event = value; ++ } ++ } ++ p_buf = p_buf->next; ++ } /* while (p_buf) */ ++ ++ dwrq->length = event - extra; ++ dwrq->flags = 0; /* todo */ ++ ++ return 0; ++} ++ ++#endif /* WIRELESS_EXT > 13 */ ++ ++ ++static int ++wl_iw_set_essid( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wlc_ssid_t ssid; ++ int error; ++ ++ AP6211_DEBUG("%s: SIOCSIWESSID\n", dev->name); ++ ++ /* default Broadcast SSID */ ++ memset(&ssid, 0, sizeof(ssid)); ++ if (dwrq->length && extra) { ++#if WIRELESS_EXT > 20 ++ ssid.SSID_len = MIN(sizeof(ssid.SSID), dwrq->length); ++#else ++ ssid.SSID_len = MIN(sizeof(ssid.SSID), dwrq->length-1); ++#endif ++ memcpy(ssid.SSID, extra, ssid.SSID_len); ++ ssid.SSID_len = htod32(ssid.SSID_len); ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid)))) ++ return error; ++ } ++ /* If essid null then it is "iwconfig essid off" command */ ++ else { ++ scb_val_t scbval; ++ bzero(&scbval, sizeof(scb_val_t)); ++ if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)))) ++ return error; ++ } ++ return 0; ++} ++ ++static int ++wl_iw_get_essid( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wlc_ssid_t ssid; ++ int error; ++ ++ AP6211_DEBUG("%s: SIOCGIWESSID\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) { ++ AP6211_ERR("Error getting the SSID\n"); ++ return error; ++ } ++ ++ ssid.SSID_len = dtoh32(ssid.SSID_len); ++ ++ /* Get the current SSID */ ++ memcpy(extra, ssid.SSID, ssid.SSID_len); ++ ++ dwrq->length = ssid.SSID_len; ++ ++ dwrq->flags = 1; /* active */ ++ ++ return 0; ++} ++ ++static int ++wl_iw_set_nick( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_iw_t *iw = IW_DEV_IF(dev); ++ AP6211_DEBUG("%s: SIOCSIWNICKN\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ /* Check the size of the string */ ++ if (dwrq->length > sizeof(iw->nickname)) ++ return -E2BIG; ++ ++ memcpy(iw->nickname, extra, dwrq->length); ++ iw->nickname[dwrq->length - 1] = '\0'; ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_nick( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_iw_t *iw = IW_DEV_IF(dev); ++ AP6211_DEBUG("%s: SIOCGIWNICKN\n", dev->name); ++ ++ if (!extra) ++ return -EINVAL; ++ ++ strcpy(extra, iw->nickname); ++ dwrq->length = strlen(extra) + 1; ++ ++ return 0; ++} ++ ++static int wl_iw_set_rate( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ wl_rateset_t rateset; ++ int error, rate, i, error_bg, error_a; ++ ++ AP6211_DEBUG("%s: SIOCSIWRATE\n", dev->name); ++ ++ /* Get current rateset */ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) ++ return error; ++ ++ rateset.count = dtoh32(rateset.count); ++ ++ if (vwrq->value < 0) { ++ /* Select maximum rate */ ++ rate = rateset.rates[rateset.count - 1] & 0x7f; ++ } else if (vwrq->value < rateset.count) { ++ /* Select rate by rateset index */ ++ rate = rateset.rates[vwrq->value] & 0x7f; ++ } else { ++ /* Specified rate in bps */ ++ rate = vwrq->value / 500000; ++ } ++ ++ if (vwrq->fixed) { ++ /* ++ Set rate override, ++ Since the is a/b/g-blind, both a/bg_rate are enforced. ++ */ ++ error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate); ++ error_a = dev_wlc_intvar_set(dev, "a_rate", rate); ++ ++ if (error_bg && error_a) ++ return (error_bg | error_a); ++ } else { ++ /* ++ clear rate override ++ Since the is a/b/g-blind, both a/bg_rate are enforced. ++ */ ++ /* 0 is for clearing rate override */ ++ error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0); ++ /* 0 is for clearing rate override */ ++ error_a = dev_wlc_intvar_set(dev, "a_rate", 0); ++ ++ if (error_bg && error_a) ++ return (error_bg | error_a); ++ ++ /* Remove rates above selected rate */ ++ for (i = 0; i < rateset.count; i++) ++ if ((rateset.rates[i] & 0x7f) > rate) ++ break; ++ rateset.count = htod32(i); ++ ++ /* Set current rateset */ ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset, sizeof(rateset)))) ++ return error; ++ } ++ ++ return 0; ++} ++ ++static int wl_iw_get_rate( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, rate; ++ ++ AP6211_DEBUG("%s: SIOCGIWRATE\n", dev->name); ++ ++ /* Report the current tx rate */ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate)))) ++ return error; ++ rate = dtoh32(rate); ++ vwrq->value = rate * 500000; ++ ++ return 0; ++} ++ ++static int ++wl_iw_set_rts( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, rts; ++ ++ AP6211_DEBUG("%s: SIOCSIWRTS\n", dev->name); ++ ++ if (vwrq->disabled) ++ rts = DOT11_DEFAULT_RTS_LEN; ++ else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN) ++ return -EINVAL; ++ else ++ rts = vwrq->value; ++ ++ if ((error = dev_wlc_intvar_set(dev, "rtsthresh", rts))) ++ return error; ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_rts( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, rts; ++ ++ AP6211_DEBUG("%s: SIOCGIWRTS\n", dev->name); ++ ++ if ((error = dev_wlc_intvar_get(dev, "rtsthresh", &rts))) ++ return error; ++ ++ vwrq->value = rts; ++ vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN); ++ vwrq->fixed = 1; ++ ++ return 0; ++} ++ ++static int ++wl_iw_set_frag( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, frag; ++ ++ AP6211_DEBUG("%s: SIOCSIWFRAG\n", dev->name); ++ ++ if (vwrq->disabled) ++ frag = DOT11_DEFAULT_FRAG_LEN; ++ else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN) ++ return -EINVAL; ++ else ++ frag = vwrq->value; ++ ++ if ((error = dev_wlc_intvar_set(dev, "fragthresh", frag))) ++ return error; ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_frag( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, fragthreshold; ++ ++ AP6211_DEBUG("%s: SIOCGIWFRAG\n", dev->name); ++ ++ if ((error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold))) ++ return error; ++ ++ vwrq->value = fragthreshold; ++ vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN); ++ vwrq->fixed = 1; ++ ++ return 0; ++} ++ ++static int ++wl_iw_set_txpow( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, disable; ++ uint16 txpwrmw; ++ AP6211_DEBUG("%s: SIOCSIWTXPOW\n", dev->name); ++ ++ /* Make sure radio is off or on as far as software is concerned */ ++ disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0; ++ disable += WL_RADIO_SW_DISABLE << 16; ++ ++ disable = htod32(disable); ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable)))) ++ return error; ++ ++ /* If Radio is off, nothing more to do */ ++ if (disable & WL_RADIO_SW_DISABLE) ++ return 0; ++ ++ /* Only handle mW */ ++ if (!(vwrq->flags & IW_TXPOW_MWATT)) ++ return -EINVAL; ++ ++ /* Value < 0 means just "on" or "off" */ ++ if (vwrq->value < 0) ++ return 0; ++ ++ if (vwrq->value > 0xffff) txpwrmw = 0xffff; ++ else txpwrmw = (uint16)vwrq->value; ++ ++ ++ error = dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw))); ++ return error; ++} ++ ++static int ++wl_iw_get_txpow( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, disable, txpwrdbm; ++ uint8 result; ++ ++ AP6211_DEBUG("%s: SIOCGIWTXPOW\n", dev->name); ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable))) || ++ (error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm))) ++ return error; ++ ++ disable = dtoh32(disable); ++ result = (uint8)(txpwrdbm & ~WL_TXPWR_OVERRIDE); ++ vwrq->value = (int32)bcm_qdbm_to_mw(result); ++ vwrq->fixed = 0; ++ vwrq->disabled = (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0; ++ vwrq->flags = IW_TXPOW_MWATT; ++ ++ return 0; ++} ++ ++#if WIRELESS_EXT > 10 ++static int ++wl_iw_set_retry( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, lrl, srl; ++ ++ AP6211_DEBUG("%s: SIOCSIWRETRY\n", dev->name); ++ ++ /* Do not handle "off" or "lifetime" */ ++ if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME)) ++ return -EINVAL; ++ ++ /* Handle "[min|max] limit" */ ++ if (vwrq->flags & IW_RETRY_LIMIT) { ++ /* "max limit" or just "limit" */ ++#if WIRELESS_EXT > 20 ++ if ((vwrq->flags & IW_RETRY_LONG) ||(vwrq->flags & IW_RETRY_MAX) || ++ !((vwrq->flags & IW_RETRY_SHORT) || (vwrq->flags & IW_RETRY_MIN))) { ++#else ++ if ((vwrq->flags & IW_RETRY_MAX) || !(vwrq->flags & IW_RETRY_MIN)) { ++#endif /* WIRELESS_EXT > 20 */ ++ ++ lrl = htod32(vwrq->value); ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(lrl)))) ++ return error; ++ } ++ /* "min limit" or just "limit" */ ++#if WIRELESS_EXT > 20 ++ if ((vwrq->flags & IW_RETRY_SHORT) ||(vwrq->flags & IW_RETRY_MIN) || ++ !((vwrq->flags & IW_RETRY_LONG) || (vwrq->flags & IW_RETRY_MAX))) { ++#else ++ if ((vwrq->flags & IW_RETRY_MIN) || !(vwrq->flags & IW_RETRY_MAX)) { ++#endif /* WIRELESS_EXT > 20 */ ++ ++ srl = htod32(vwrq->value); ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl, sizeof(srl)))) ++ return error; ++ } ++ } ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_retry( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, lrl, srl; ++ ++ AP6211_DEBUG("%s: SIOCGIWRETRY\n", dev->name); ++ ++ vwrq->disabled = 0; /* Can't be disabled */ ++ ++ /* Do not handle lifetime queries */ ++ if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) ++ return -EINVAL; ++ ++ /* Get retry limits */ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl))) || ++ (error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl)))) ++ return error; ++ ++ lrl = dtoh32(lrl); ++ srl = dtoh32(srl); ++ ++ /* Note : by default, display the min retry number */ ++ if (vwrq->flags & IW_RETRY_MAX) { ++ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; ++ vwrq->value = lrl; ++ } else { ++ vwrq->flags = IW_RETRY_LIMIT; ++ vwrq->value = srl; ++ if (srl != lrl) ++ vwrq->flags |= IW_RETRY_MIN; ++ } ++ ++ return 0; ++} ++#endif /* WIRELESS_EXT > 10 */ ++ ++static int ++wl_iw_set_encode( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_wsec_key_t key; ++ int error, val, wsec; ++ ++ AP6211_DEBUG("%s: SIOCSIWENCODE\n", dev->name); ++ ++ memset(&key, 0, sizeof(key)); ++ ++ if ((dwrq->flags & IW_ENCODE_INDEX) == 0) { ++ /* Find the current key */ ++ for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) { ++ val = htod32(key.index); ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val)))) ++ return error; ++ val = dtoh32(val); ++ if (val) ++ break; ++ } ++ /* Default to 0 */ ++ if (key.index == DOT11_MAX_DEFAULT_KEYS) ++ key.index = 0; ++ } else { ++ key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1; ++ if (key.index >= DOT11_MAX_DEFAULT_KEYS) ++ return -EINVAL; ++ } ++ ++ /* Interpret "off" to mean no encryption */ ++ wsec = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED; ++ ++ if ((error = dev_wlc_intvar_set(dev, "wsec", wsec))) ++ return error; ++ ++ /* Old API used to pass a NULL pointer instead of IW_ENCODE_NOKEY */ ++ if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) { ++ /* Just select a new current key */ ++ val = htod32(key.index); ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val, sizeof(val)))) ++ return error; ++ } else { ++ key.len = dwrq->length; ++ ++ if (dwrq->length > sizeof(key.data)) ++ return -EINVAL; ++ ++ memcpy(key.data, extra, dwrq->length); ++ ++ key.flags = WL_PRIMARY_KEY; ++ switch (key.len) { ++ case WEP1_KEY_SIZE: ++ key.algo = CRYPTO_ALGO_WEP1; ++ break; ++ case WEP128_KEY_SIZE: ++ key.algo = CRYPTO_ALGO_WEP128; ++ break; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) ++ case TKIP_KEY_SIZE: ++ key.algo = CRYPTO_ALGO_TKIP; ++ break; ++#endif ++ case AES_KEY_SIZE: ++ key.algo = CRYPTO_ALGO_AES_CCM; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* Set the new key/index */ ++ swap_key_from_BE(&key); ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)))) ++ return error; ++ } ++ ++ /* Interpret "restricted" to mean shared key authentication */ ++ val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0; ++ val = htod32(val); ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val)))) ++ return error; ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_encode( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_wsec_key_t key; ++ int error, val, wsec, auth; ++ ++ AP6211_DEBUG("%s: SIOCGIWENCODE\n", dev->name); ++ ++ /* assure default values of zero for things we don't touch */ ++ bzero(&key, sizeof(wl_wsec_key_t)); ++ ++ if ((dwrq->flags & IW_ENCODE_INDEX) == 0) { ++ /* Find the current key */ ++ for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) { ++ val = key.index; ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val)))) ++ return error; ++ val = dtoh32(val); ++ if (val) ++ break; ++ } ++ } else ++ key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1; ++ ++ if (key.index >= DOT11_MAX_DEFAULT_KEYS) ++ key.index = 0; ++ ++ /* Get info */ ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec))) || ++ (error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth)))) ++ return error; ++ ++ swap_key_to_BE(&key); ++ ++ wsec = dtoh32(wsec); ++ auth = dtoh32(auth); ++ /* Get key length */ ++ dwrq->length = MIN(IW_ENCODING_TOKEN_MAX, key.len); ++ ++ /* Get flags */ ++ dwrq->flags = key.index + 1; ++ if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))) { ++ /* Interpret "off" to mean no encryption */ ++ dwrq->flags |= IW_ENCODE_DISABLED; ++ } ++ if (auth) { ++ /* Interpret "restricted" to mean shared key authentication */ ++ dwrq->flags |= IW_ENCODE_RESTRICTED; ++ } ++ ++ /* Get key */ ++ if (dwrq->length && extra) ++ memcpy(extra, key.data, dwrq->length); ++ ++ return 0; ++} ++ ++static int ++wl_iw_set_power( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, pm; ++ ++ AP6211_DEBUG("%s: SIOCSIWPOWER\n", dev->name); ++ ++ pm = vwrq->disabled ? PM_OFF : PM_MAX; ++ ++ pm = htod32(pm); ++ if ((error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)))) ++ return error; ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_power( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error, pm; ++ ++ AP6211_DEBUG("%s: SIOCGIWPOWER\n", dev->name); ++ ++ if ((error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm)))) ++ return error; ++ ++ pm = dtoh32(pm); ++ vwrq->disabled = pm ? 0 : 1; ++ vwrq->flags = IW_POWER_ALL_R; ++ ++ return 0; ++} ++ ++#if WIRELESS_EXT > 17 ++static int ++wl_iw_set_wpaie( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *iwp, ++ char *extra ++) ++{ ++ dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length); ++ ++ return 0; ++} ++ ++static int ++wl_iw_get_wpaie( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *iwp, ++ char *extra ++) ++{ ++ AP6211_DEBUG("%s: SIOCGIWGENIE\n", dev->name); ++ iwp->length = 64; ++ dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length); ++ return 0; ++} ++ ++static int ++wl_iw_set_encodeext( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *dwrq, ++ char *extra ++) ++{ ++ wl_wsec_key_t key; ++ int error; ++ struct iw_encode_ext *iwe; ++ ++ AP6211_DEBUG("%s: SIOCSIWENCODEEXT\n", dev->name); ++ ++ memset(&key, 0, sizeof(key)); ++ iwe = (struct iw_encode_ext *)extra; ++ ++ /* disable encryption completely */ ++ if (dwrq->flags & IW_ENCODE_DISABLED) { ++ ++ } ++ ++ /* get the key index */ ++ key.index = 0; ++ if (dwrq->flags & IW_ENCODE_INDEX) ++ key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1; ++ ++ key.len = iwe->key_len; ++ ++ /* Instead of bcast for ea address for default wep keys, driver needs it to be Null */ ++ if (!ETHER_ISMULTI(iwe->addr.sa_data)) ++ bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea, ETHER_ADDR_LEN); ++ ++ /* check for key index change */ ++ if (key.len == 0) { ++ if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { ++ AP6211_DEBUG("Changing the the primary Key to %d\n", key.index); ++ /* change the key index .... */ ++ key.index = htod32(key.index); ++ error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, ++ &key.index, sizeof(key.index)); ++ if (error) ++ return error; ++ } ++ /* key delete */ ++ else { ++ swap_key_from_BE(&key); ++ error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); ++ if (error) ++ return error; ++ } ++ } ++#if (defined(BCMSUP_PSK) && defined(WLFBT)) ++ /* This case is used to allow an external 802.1x supplicant ++ * to pass the PMK to the in-driver supplicant for use in ++ * the 4-way handshake. ++ */ ++ else if (iwe->alg == IW_ENCODE_ALG_PMK) { ++ int j; ++ wsec_pmk_t pmk; ++ char keystring[WSEC_MAX_PSK_LEN + 1]; ++ char* charptr = keystring; ++ uint len; ++ ++ /* copy the raw hex key to the appropriate format */ ++ for (j = 0; j < (WSEC_MAX_PSK_LEN / 2); j++) { ++ sprintf(charptr, "%02x", iwe->key[j]); ++ charptr += 2; ++ } ++ len = strlen(keystring); ++ pmk.key_len = htod16(len); ++ bcopy(keystring, pmk.key, len); ++ pmk.flags = htod16(WSEC_PASSPHRASE); ++ ++ error = dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk)); ++ if (error) ++ return error; ++ } ++#endif /* (defined (BCMSUP_PSK) && defined(WLFBT)) */ ++ ++ else { ++ if (iwe->key_len > sizeof(key.data)) ++ return -EINVAL; ++ ++ AP6211_DEBUG("Setting the key index %d\n", key.index); ++ if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { ++ AP6211_DEBUG("key is a Primary Key\n"); ++ key.flags = WL_PRIMARY_KEY; ++ } ++ ++ bcopy((void *)iwe->key, key.data, iwe->key_len); ++ ++ if (iwe->alg == IW_ENCODE_ALG_TKIP) { ++ uint8 keybuf[8]; ++ bcopy(&key.data[24], keybuf, sizeof(keybuf)); ++ bcopy(&key.data[16], &key.data[24], sizeof(keybuf)); ++ bcopy(keybuf, &key.data[16], sizeof(keybuf)); ++ } ++ ++ /* rx iv */ ++ if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { ++ uchar *ivptr; ++ ivptr = (uchar *)iwe->rx_seq; ++ key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | ++ (ivptr[3] << 8) | ivptr[2]; ++ key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; ++ key.iv_initialized = TRUE; ++ } ++ ++ switch (iwe->alg) { ++ case IW_ENCODE_ALG_NONE: ++ key.algo = CRYPTO_ALGO_OFF; ++ break; ++ case IW_ENCODE_ALG_WEP: ++ if (iwe->key_len == WEP1_KEY_SIZE) ++ key.algo = CRYPTO_ALGO_WEP1; ++ else ++ key.algo = CRYPTO_ALGO_WEP128; ++ break; ++ case IW_ENCODE_ALG_TKIP: ++ key.algo = CRYPTO_ALGO_TKIP; ++ break; ++ case IW_ENCODE_ALG_CCMP: ++ key.algo = CRYPTO_ALGO_AES_CCM; ++ break; ++ default: ++ break; ++ } ++ swap_key_from_BE(&key); ++ ++ dhd_wait_pend8021x(dev); ++ ++ error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); ++ if (error) ++ return error; ++ } ++ return 0; ++} ++ ++ ++#if WIRELESS_EXT > 17 ++struct { ++ pmkid_list_t pmkids; ++ pmkid_t foo[MAXPMKID-1]; ++} pmkid_list; ++static int ++wl_iw_set_pmksa( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ struct iw_pmksa *iwpmksa; ++ uint i; ++ char eabuf[ETHER_ADDR_STR_LEN]; ++ pmkid_t * pmkid_array = pmkid_list.pmkids.pmkid; ++ ++ AP6211_DEBUG("%s: SIOCSIWPMKSA\n", dev->name); ++ iwpmksa = (struct iw_pmksa *)extra; ++ bzero((char *)eabuf, ETHER_ADDR_STR_LEN); ++ if (iwpmksa->cmd == IW_PMKSA_FLUSH) { ++ AP6211_DEBUG("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n"); ++ bzero((char *)&pmkid_list, sizeof(pmkid_list)); ++ } ++ if (iwpmksa->cmd == IW_PMKSA_REMOVE) { ++ pmkid_list_t pmkid, *pmkidptr; ++ pmkidptr = &pmkid; ++ bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN); ++ bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN); ++ { ++ uint j; ++ AP6211_DEBUG("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ", ++ bcm_ether_ntoa(&pmkidptr->pmkid[0].BSSID, ++ eabuf)); ++ for (j = 0; j < WPA2_PMKID_LEN; j++) ++ AP6211_DUMP("%02x ", pmkidptr->pmkid[0].PMKID[j]); ++ AP6211_DUMP("\n"); ++ } ++ for (i = 0; i < pmkid_list.pmkids.npmkid; i++) ++ if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_array[i].BSSID, ++ ETHER_ADDR_LEN)) ++ break; ++ for (; i < pmkid_list.pmkids.npmkid; i++) { ++ bcopy(&pmkid_array[i+1].BSSID, ++ &pmkid_array[i].BSSID, ++ ETHER_ADDR_LEN); ++ bcopy(&pmkid_array[i+1].PMKID, ++ &pmkid_array[i].PMKID, ++ WPA2_PMKID_LEN); ++ } ++ pmkid_list.pmkids.npmkid--; ++ } ++ if (iwpmksa->cmd == IW_PMKSA_ADD) { ++ bcopy(&iwpmksa->bssid.sa_data[0], ++ &pmkid_array[pmkid_list.pmkids.npmkid].BSSID, ++ ETHER_ADDR_LEN); ++ bcopy(&iwpmksa->pmkid[0], &pmkid_array[pmkid_list.pmkids.npmkid].PMKID, ++ WPA2_PMKID_LEN); ++ { ++ uint j; ++ uint k; ++ k = pmkid_list.pmkids.npmkid; ++ BCM_REFERENCE(k); ++ AP6211_DEBUG("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ", ++ bcm_ether_ntoa(&pmkid_array[k].BSSID, ++ eabuf)); ++ for (j = 0; j < WPA2_PMKID_LEN; j++) ++ AP6211_DUMP("%02x ", pmkid_array[k].PMKID[j]); ++ AP6211_DUMP("\n"); ++ } ++ pmkid_list.pmkids.npmkid++; ++ } ++ AP6211_DEBUG("PRINTING pmkid LIST - No of elements %d\n", pmkid_list.pmkids.npmkid); ++ for (i = 0; i < pmkid_list.pmkids.npmkid; i++) { ++ uint j; ++ AP6211_DEBUG("PMKID[%d]: %s = ", i, ++ bcm_ether_ntoa(&pmkid_array[i].BSSID, ++ eabuf)); ++ for (j = 0; j < WPA2_PMKID_LEN; j++) ++ AP6211_DUMP("%02x ", pmkid_array[i].PMKID[j]); ++ AP6211_DEBUG("\n"); ++ } ++ AP6211_DEBUG("\n"); ++ dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, sizeof(pmkid_list)); ++ return 0; ++} ++#endif /* WIRELESS_EXT > 17 */ ++ ++static int ++wl_iw_get_encodeext( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ AP6211_DEBUG("%s: SIOCGIWENCODEEXT\n", dev->name); ++ return 0; ++} ++ ++static int ++wl_iw_set_wpaauth( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error = 0; ++ int paramid; ++ int paramval; ++ uint32 cipher_combined; ++ int val = 0; ++ wl_iw_t *iw = IW_DEV_IF(dev); ++ ++ AP6211_DEBUG("%s: SIOCSIWAUTH\n", dev->name); ++ ++ paramid = vwrq->flags & IW_AUTH_INDEX; ++ paramval = vwrq->value; ++ ++ AP6211_DEBUG("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n", ++ dev->name, paramid, paramval); ++ ++ switch (paramid) { ++ ++ case IW_AUTH_WPA_VERSION: ++ /* supported wpa version disabled or wpa or wpa2 */ ++ if (paramval & IW_AUTH_WPA_VERSION_DISABLED) ++ val = WPA_AUTH_DISABLED; ++ else if (paramval & (IW_AUTH_WPA_VERSION_WPA)) ++ val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; ++ else if (paramval & IW_AUTH_WPA_VERSION_WPA2) ++ val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; ++ AP6211_DEBUG("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val); ++ if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) ++ return error; ++ break; ++ ++ case IW_AUTH_CIPHER_PAIRWISE: ++ case IW_AUTH_CIPHER_GROUP: ++ ++ if (paramid == IW_AUTH_CIPHER_PAIRWISE) { ++ iw->pwsec = paramval; ++ } ++ else { ++ iw->gwsec = paramval; ++ } ++ ++ if ((error = dev_wlc_intvar_get(dev, "wsec", &val))) ++ return error; ++ ++ cipher_combined = iw->gwsec | iw->pwsec; ++ val &= ~(WEP_ENABLED | TKIP_ENABLED | AES_ENABLED); ++ if (cipher_combined & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) ++ val |= WEP_ENABLED; ++ if (cipher_combined & IW_AUTH_CIPHER_TKIP) ++ val |= TKIP_ENABLED; ++ if (cipher_combined & IW_AUTH_CIPHER_CCMP) ++ val |= AES_ENABLED; ++ ++ if (iw->privacy_invoked && !val) { ++ AP6211_DEBUG("%s: %s: 'Privacy invoked' TRUE but clearing wsec, assuming " ++ "we're a WPS enrollee\n", dev->name, __FUNCTION__); ++ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) { ++ AP6211_DEBUG("Failed to set iovar is_WPS_enrollee\n"); ++ return error; ++ } ++ } else if (val) { ++ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) { ++ AP6211_DEBUG("Failed to clear iovar is_WPS_enrollee\n"); ++ return error; ++ } ++ } ++ ++ if ((error = dev_wlc_intvar_set(dev, "wsec", val))) ++ return error; ++#ifdef WLFBT ++ if ((paramid == IW_AUTH_CIPHER_PAIRWISE) && (val | AES_ENABLED)) { ++ if ((error = dev_wlc_intvar_set(dev, "sup_wpa", 1))) ++ return error; ++ } ++ else if (val == 0) { ++ if ((error = dev_wlc_intvar_set(dev, "sup_wpa", 0))) ++ return error; ++ } ++#endif /* WLFBT */ ++ break; ++ ++ case IW_AUTH_KEY_MGMT: ++ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) ++ return error; ++ ++ if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { ++ if (paramval & IW_AUTH_KEY_MGMT_PSK) ++ val = WPA_AUTH_PSK; ++ else ++ val = WPA_AUTH_UNSPECIFIED; ++ } ++ else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { ++ if (paramval & IW_AUTH_KEY_MGMT_PSK) ++ val = WPA2_AUTH_PSK; ++ else ++ val = WPA2_AUTH_UNSPECIFIED; ++ } ++ AP6211_DEBUG("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val); ++ if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) ++ return error; ++ break; ++ ++ case IW_AUTH_TKIP_COUNTERMEASURES: ++ dev_wlc_bufvar_set(dev, "tkip_countermeasures", (char *)¶mval, 1); ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ /* open shared */ ++ AP6211_ERR("Setting the D11auth %d\n", paramval); ++ if (paramval & IW_AUTH_ALG_OPEN_SYSTEM) ++ val = 0; ++ else if (paramval & IW_AUTH_ALG_SHARED_KEY) ++ val = 1; ++ else ++ error = 1; ++ if (!error && (error = dev_wlc_intvar_set(dev, "auth", val))) ++ return error; ++ break; ++ ++ case IW_AUTH_WPA_ENABLED: ++ if (paramval == 0) { ++ val = 0; ++ AP6211_DEBUG("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val); ++ error = dev_wlc_intvar_set(dev, "wpa_auth", val); ++ return error; ++ } ++ else { ++ /* If WPA is enabled, wpa_auth is set elsewhere */ ++ } ++ break; ++ ++ case IW_AUTH_DROP_UNENCRYPTED: ++ dev_wlc_bufvar_set(dev, "wsec_restrict", (char *)¶mval, 1); ++ break; ++ ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol", (char *)¶mval, 1); ++ break; ++ ++#if WIRELESS_EXT > 17 ++ ++ case IW_AUTH_ROAMING_CONTROL: ++ AP6211_DEBUG("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__); ++ /* driver control or user space app control */ ++ break; ++ ++ case IW_AUTH_PRIVACY_INVOKED: { ++ int wsec; ++ ++ if (paramval == 0) { ++ iw->privacy_invoked = FALSE; ++ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) { ++ AP6211_DEBUG("Failed to clear iovar is_WPS_enrollee\n"); ++ return error; ++ } ++ } else { ++ iw->privacy_invoked = TRUE; ++ if ((error = dev_wlc_intvar_get(dev, "wsec", &wsec))) ++ return error; ++ ++ if (!WSEC_ENABLED(wsec)) { ++ /* if privacy is true, but wsec is false, we are a WPS enrollee */ ++ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) { ++ AP6211_DEBUG("Failed to set iovar is_WPS_enrollee\n"); ++ return error; ++ } ++ } else { ++ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) { ++ AP6211_DEBUG("Failed to clear iovar is_WPS_enrollee\n"); ++ return error; ++ } ++ } ++ } ++ break; ++ } ++ ++ ++#endif /* WIRELESS_EXT > 17 */ ++ ++ ++ default: ++ break; ++ } ++ return 0; ++} ++#define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK)) ++ ++static int ++wl_iw_get_wpaauth( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *vwrq, ++ char *extra ++) ++{ ++ int error; ++ int paramid; ++ int paramval = 0; ++ int val; ++ wl_iw_t *iw = IW_DEV_IF(dev); ++ ++ AP6211_DEBUG("%s: SIOCGIWAUTH\n", dev->name); ++ ++ paramid = vwrq->flags & IW_AUTH_INDEX; ++ ++ switch (paramid) { ++ case IW_AUTH_WPA_VERSION: ++ /* supported wpa version disabled or wpa or wpa2 */ ++ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) ++ return error; ++ if (val & (WPA_AUTH_NONE | WPA_AUTH_DISABLED)) ++ paramval = IW_AUTH_WPA_VERSION_DISABLED; ++ else if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) ++ paramval = IW_AUTH_WPA_VERSION_WPA; ++ else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) ++ paramval = IW_AUTH_WPA_VERSION_WPA2; ++ break; ++ ++ case IW_AUTH_CIPHER_PAIRWISE: ++ paramval = iw->pwsec; ++ break; ++ ++ case IW_AUTH_CIPHER_GROUP: ++ paramval = iw->gwsec; ++ break; ++ ++ case IW_AUTH_KEY_MGMT: ++ /* psk, 1x */ ++ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) ++ return error; ++ if (VAL_PSK(val)) ++ paramval = IW_AUTH_KEY_MGMT_PSK; ++ else ++ paramval = IW_AUTH_KEY_MGMT_802_1X; ++ ++ break; ++ case IW_AUTH_TKIP_COUNTERMEASURES: ++ dev_wlc_bufvar_get(dev, "tkip_countermeasures", (char *)¶mval, 1); ++ break; ++ ++ case IW_AUTH_DROP_UNENCRYPTED: ++ dev_wlc_bufvar_get(dev, "wsec_restrict", (char *)¶mval, 1); ++ break; ++ ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol", (char *)¶mval, 1); ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ /* open, shared, leap */ ++ if ((error = dev_wlc_intvar_get(dev, "auth", &val))) ++ return error; ++ if (!val) ++ paramval = IW_AUTH_ALG_OPEN_SYSTEM; ++ else ++ paramval = IW_AUTH_ALG_SHARED_KEY; ++ break; ++ case IW_AUTH_WPA_ENABLED: ++ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) ++ return error; ++ if (val) ++ paramval = TRUE; ++ else ++ paramval = FALSE; ++ break; ++ ++#if WIRELESS_EXT > 17 ++ ++ case IW_AUTH_ROAMING_CONTROL: ++ AP6211_ERR("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__); ++ /* driver control or user space app control */ ++ break; ++ ++ case IW_AUTH_PRIVACY_INVOKED: ++ paramval = iw->privacy_invoked; ++ break; ++ ++#endif /* WIRELESS_EXT > 17 */ ++ } ++ vwrq->value = paramval; ++ return 0; ++} ++#endif /* WIRELESS_EXT > 17 */ ++ ++static const iw_handler wl_iw_handler[] = ++{ ++ (iw_handler) wl_iw_config_commit, /* SIOCSIWCOMMIT */ ++ (iw_handler) wl_iw_get_name, /* SIOCGIWNAME */ ++ (iw_handler) NULL, /* SIOCSIWNWID */ ++ (iw_handler) NULL, /* SIOCGIWNWID */ ++ (iw_handler) wl_iw_set_freq, /* SIOCSIWFREQ */ ++ (iw_handler) wl_iw_get_freq, /* SIOCGIWFREQ */ ++ (iw_handler) wl_iw_set_mode, /* SIOCSIWMODE */ ++ (iw_handler) wl_iw_get_mode, /* SIOCGIWMODE */ ++ (iw_handler) NULL, /* SIOCSIWSENS */ ++ (iw_handler) NULL, /* SIOCGIWSENS */ ++ (iw_handler) NULL, /* SIOCSIWRANGE */ ++ (iw_handler) wl_iw_get_range, /* SIOCGIWRANGE */ ++ (iw_handler) NULL, /* SIOCSIWPRIV */ ++ (iw_handler) NULL, /* SIOCGIWPRIV */ ++ (iw_handler) NULL, /* SIOCSIWSTATS */ ++ (iw_handler) NULL, /* SIOCGIWSTATS */ ++ (iw_handler) wl_iw_set_spy, /* SIOCSIWSPY */ ++ (iw_handler) wl_iw_get_spy, /* SIOCGIWSPY */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) wl_iw_set_wap, /* SIOCSIWAP */ ++ (iw_handler) wl_iw_get_wap, /* SIOCGIWAP */ ++#if WIRELESS_EXT > 17 ++ (iw_handler) wl_iw_mlme, /* SIOCSIWMLME */ ++#else ++ (iw_handler) NULL, /* -- hole -- */ ++#endif ++ (iw_handler) wl_iw_iscan_get_aplist, /* SIOCGIWAPLIST */ ++#if WIRELESS_EXT > 13 ++ (iw_handler) wl_iw_iscan_set_scan, /* SIOCSIWSCAN */ ++ (iw_handler) wl_iw_iscan_get_scan, /* SIOCGIWSCAN */ ++#else /* WIRELESS_EXT > 13 */ ++ (iw_handler) NULL, /* SIOCSIWSCAN */ ++ (iw_handler) NULL, /* SIOCGIWSCAN */ ++#endif /* WIRELESS_EXT > 13 */ ++ (iw_handler) wl_iw_set_essid, /* SIOCSIWESSID */ ++ (iw_handler) wl_iw_get_essid, /* SIOCGIWESSID */ ++ (iw_handler) wl_iw_set_nick, /* SIOCSIWNICKN */ ++ (iw_handler) wl_iw_get_nick, /* SIOCGIWNICKN */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) wl_iw_set_rate, /* SIOCSIWRATE */ ++ (iw_handler) wl_iw_get_rate, /* SIOCGIWRATE */ ++ (iw_handler) wl_iw_set_rts, /* SIOCSIWRTS */ ++ (iw_handler) wl_iw_get_rts, /* SIOCGIWRTS */ ++ (iw_handler) wl_iw_set_frag, /* SIOCSIWFRAG */ ++ (iw_handler) wl_iw_get_frag, /* SIOCGIWFRAG */ ++ (iw_handler) wl_iw_set_txpow, /* SIOCSIWTXPOW */ ++ (iw_handler) wl_iw_get_txpow, /* SIOCGIWTXPOW */ ++#if WIRELESS_EXT > 10 ++ (iw_handler) wl_iw_set_retry, /* SIOCSIWRETRY */ ++ (iw_handler) wl_iw_get_retry, /* SIOCGIWRETRY */ ++#endif /* WIRELESS_EXT > 10 */ ++ (iw_handler) wl_iw_set_encode, /* SIOCSIWENCODE */ ++ (iw_handler) wl_iw_get_encode, /* SIOCGIWENCODE */ ++ (iw_handler) wl_iw_set_power, /* SIOCSIWPOWER */ ++ (iw_handler) wl_iw_get_power, /* SIOCGIWPOWER */ ++#if WIRELESS_EXT > 17 ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) wl_iw_set_wpaie, /* SIOCSIWGENIE */ ++ (iw_handler) wl_iw_get_wpaie, /* SIOCGIWGENIE */ ++ (iw_handler) wl_iw_set_wpaauth, /* SIOCSIWAUTH */ ++ (iw_handler) wl_iw_get_wpaauth, /* SIOCGIWAUTH */ ++ (iw_handler) wl_iw_set_encodeext, /* SIOCSIWENCODEEXT */ ++ (iw_handler) wl_iw_get_encodeext, /* SIOCGIWENCODEEXT */ ++ (iw_handler) wl_iw_set_pmksa, /* SIOCSIWPMKSA */ ++#endif /* WIRELESS_EXT > 17 */ ++}; ++ ++#if WIRELESS_EXT > 12 ++enum { ++ WL_IW_SET_LEDDC = SIOCIWFIRSTPRIV, ++ WL_IW_SET_VLANMODE, ++ WL_IW_SET_PM ++}; ++ ++static iw_handler wl_iw_priv_handler[] = { ++ wl_iw_set_leddc, ++ wl_iw_set_vlanmode, ++ wl_iw_set_pm ++}; ++ ++static struct iw_priv_args wl_iw_priv_args[] = { ++ { ++ WL_IW_SET_LEDDC, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ++ 0, ++ "set_leddc" ++ }, ++ { ++ WL_IW_SET_VLANMODE, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ++ 0, ++ "set_vlanmode" ++ }, ++ { ++ WL_IW_SET_PM, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, ++ 0, ++ "set_pm" ++ } ++}; ++ ++const struct iw_handler_def wl_iw_handler_def = ++{ ++ .num_standard = ARRAYSIZE(wl_iw_handler), ++ .num_private = ARRAY_SIZE(wl_iw_priv_handler), ++ .num_private_args = ARRAY_SIZE(wl_iw_priv_args), ++ .standard = (iw_handler *) wl_iw_handler, ++ .private = wl_iw_priv_handler, ++ .private_args = wl_iw_priv_args, ++#if WIRELESS_EXT >= 19 ++ get_wireless_stats: dhd_get_wireless_stats, ++#endif /* WIRELESS_EXT >= 19 */ ++ }; ++#endif /* WIRELESS_EXT > 12 */ ++ ++int ++wl_iw_ioctl( ++ struct net_device *dev, ++ struct ifreq *rq, ++ int cmd ++) ++{ ++ struct iwreq *wrq = (struct iwreq *) rq; ++ struct iw_request_info info; ++ iw_handler handler; ++ char *extra = NULL; ++ size_t token_size = 1; ++ int max_tokens = 0, ret = 0; ++ ++ if (cmd < SIOCIWFIRST || ++ IW_IOCTL_IDX(cmd) >= ARRAYSIZE(wl_iw_handler) || ++ !(handler = wl_iw_handler[IW_IOCTL_IDX(cmd)])) ++ return -EOPNOTSUPP; ++ ++ switch (cmd) { ++ ++ case SIOCSIWESSID: ++ case SIOCGIWESSID: ++ case SIOCSIWNICKN: ++ case SIOCGIWNICKN: ++ max_tokens = IW_ESSID_MAX_SIZE + 1; ++ break; ++ ++ case SIOCSIWENCODE: ++ case SIOCGIWENCODE: ++#if WIRELESS_EXT > 17 ++ case SIOCSIWENCODEEXT: ++ case SIOCGIWENCODEEXT: ++#endif ++ max_tokens = IW_ENCODING_TOKEN_MAX; ++ break; ++ ++ case SIOCGIWRANGE: ++ max_tokens = sizeof(struct iw_range); ++ break; ++ ++ case SIOCGIWAPLIST: ++ token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality); ++ max_tokens = IW_MAX_AP; ++ break; ++ ++#if WIRELESS_EXT > 13 ++ case SIOCGIWSCAN: ++ if (g_iscan) ++ max_tokens = wrq->u.data.length; ++ else ++ max_tokens = IW_SCAN_MAX_DATA; ++ break; ++#endif /* WIRELESS_EXT > 13 */ ++ ++ case SIOCSIWSPY: ++ token_size = sizeof(struct sockaddr); ++ max_tokens = IW_MAX_SPY; ++ break; ++ ++ case SIOCGIWSPY: ++ token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality); ++ max_tokens = IW_MAX_SPY; ++ break; ++ default: ++ break; ++ } ++ ++ if (max_tokens && wrq->u.data.pointer) { ++ if (wrq->u.data.length > max_tokens) ++ return -E2BIG; ++ ++ if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL))) ++ return -ENOMEM; ++ ++ if (copy_from_user(extra, wrq->u.data.pointer, wrq->u.data.length * token_size)) { ++ kfree(extra); ++ return -EFAULT; ++ } ++ } ++ ++ info.cmd = cmd; ++ info.flags = 0; ++ ++ ret = handler(dev, &info, &wrq->u, extra); ++ ++ if (extra) { ++ if (copy_to_user(wrq->u.data.pointer, extra, wrq->u.data.length * token_size)) { ++ kfree(extra); ++ return -EFAULT; ++ } ++ ++ kfree(extra); ++ } ++ ++ return ret; ++} ++ ++/* Convert a connection status event into a connection status string. ++ * Returns TRUE if a matching connection status string was found. ++ */ ++bool ++wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason, ++ char* stringBuf, uint buflen) ++{ ++ typedef struct conn_fail_event_map_t { ++ uint32 inEvent; /* input: event type to match */ ++ uint32 inStatus; /* input: event status code to match */ ++ uint32 inReason; /* input: event reason code to match */ ++ const char* outName; /* output: failure type */ ++ const char* outCause; /* output: failure cause */ ++ } conn_fail_event_map_t; ++ ++ /* Map of WLC_E events to connection failure strings */ ++# define WL_IW_DONT_CARE 9999 ++ const conn_fail_event_map_t event_map [] = { ++ /* inEvent inStatus inReason */ ++ /* outName outCause */ ++ {WLC_E_SET_SSID, WLC_E_STATUS_SUCCESS, WL_IW_DONT_CARE, ++ "Conn", "Success"}, ++ {WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WL_IW_DONT_CARE, ++ "Conn", "NoNetworks"}, ++ {WLC_E_SET_SSID, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE, ++ "Conn", "ConfigMismatch"}, ++ {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_PRUNE_ENCR_MISMATCH, ++ "Conn", "EncrypMismatch"}, ++ {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_RSN_MISMATCH, ++ "Conn", "RsnMismatch"}, ++ {WLC_E_AUTH, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE, ++ "Conn", "AuthTimeout"}, ++ {WLC_E_AUTH, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE, ++ "Conn", "AuthFail"}, ++ {WLC_E_AUTH, WLC_E_STATUS_NO_ACK, WL_IW_DONT_CARE, ++ "Conn", "AuthNoAck"}, ++ {WLC_E_REASSOC, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE, ++ "Conn", "ReassocFail"}, ++ {WLC_E_REASSOC, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE, ++ "Conn", "ReassocTimeout"}, ++ {WLC_E_REASSOC, WLC_E_STATUS_ABORT, WL_IW_DONT_CARE, ++ "Conn", "ReassocAbort"}, ++ {WLC_E_PSK_SUP, WLC_SUP_KEYED, WL_IW_DONT_CARE, ++ "Sup", "ConnSuccess"}, ++ {WLC_E_PSK_SUP, WL_IW_DONT_CARE, WL_IW_DONT_CARE, ++ "Sup", "WpaHandshakeFail"}, ++ {WLC_E_DEAUTH_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE, ++ "Conn", "Deauth"}, ++ {WLC_E_DISASSOC_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE, ++ "Conn", "DisassocInd"}, ++ {WLC_E_DISASSOC, WL_IW_DONT_CARE, WL_IW_DONT_CARE, ++ "Conn", "Disassoc"} ++ }; ++ ++ const char* name = ""; ++ const char* cause = NULL; ++ int i; ++ ++ /* Search the event map table for a matching event */ ++ for (i = 0; i < sizeof(event_map)/sizeof(event_map[0]); i++) { ++ const conn_fail_event_map_t* row = &event_map[i]; ++ if (row->inEvent == event_type && ++ (row->inStatus == status || row->inStatus == WL_IW_DONT_CARE) && ++ (row->inReason == reason || row->inReason == WL_IW_DONT_CARE)) { ++ name = row->outName; ++ cause = row->outCause; ++ break; ++ } ++ } ++ ++ /* If found, generate a connection failure string and return TRUE */ ++ if (cause) { ++ memset(stringBuf, 0, buflen); ++ snprintf(stringBuf, buflen, "%s %s %02d %02d", ++ name, cause, status, reason); ++ AP6211_DEBUG("Connection status: %s\n", stringBuf); ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++} ++ ++#if (WIRELESS_EXT > 14) ++/* Check if we have received an event that indicates connection failure ++ * If so, generate a connection failure report string. ++ * The caller supplies a buffer to hold the generated string. ++ */ ++static bool ++wl_iw_check_conn_fail(wl_event_msg_t *e, char* stringBuf, uint buflen) ++{ ++ uint32 event = ntoh32(e->event_type); ++ uint32 status = ntoh32(e->status); ++ uint32 reason = ntoh32(e->reason); ++ ++ if (wl_iw_conn_status_str(event, status, reason, stringBuf, buflen)) { ++ return TRUE; ++ } else ++ { ++ return FALSE; ++ } ++} ++#endif /* WIRELESS_EXT > 14 */ ++ ++#ifndef IW_CUSTOM_MAX ++#define IW_CUSTOM_MAX 256 /* size of extra buffer used for translation of events */ ++#endif /* IW_CUSTOM_MAX */ ++ ++void ++wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) ++{ ++#if WIRELESS_EXT > 13 ++ union iwreq_data wrqu; ++ char extra[IW_CUSTOM_MAX + 1]; ++ int cmd = 0; ++ uint32 event_type = ntoh32(e->event_type); ++ uint16 flags = ntoh16(e->flags); ++ uint32 datalen = ntoh32(e->datalen); ++ uint32 status = ntoh32(e->status); ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ memset(extra, 0, sizeof(extra)); ++ ++ memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); ++ wrqu.addr.sa_family = ARPHRD_ETHER; ++ ++ switch (event_type) { ++ case WLC_E_TXFAIL: ++ cmd = IWEVTXDROP; ++ break; ++#if WIRELESS_EXT > 14 ++ case WLC_E_JOIN: ++ case WLC_E_ASSOC_IND: ++ case WLC_E_REASSOC_IND: ++ cmd = IWEVREGISTERED; ++ break; ++ case WLC_E_DEAUTH_IND: ++ case WLC_E_DISASSOC_IND: ++ cmd = SIOCGIWAP; ++ wrqu.data.length = strlen(extra); ++ bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); ++ bzero(&extra, ETHER_ADDR_LEN); ++ break; ++ ++ case WLC_E_LINK: ++ case WLC_E_NDIS_LINK: ++ cmd = SIOCGIWAP; ++ wrqu.data.length = strlen(extra); ++ if (!(flags & WLC_EVENT_MSG_LINK)) { ++ bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); ++ bzero(&extra, ETHER_ADDR_LEN); ++ } ++ break; ++ case WLC_E_ACTION_FRAME: ++ cmd = IWEVCUSTOM; ++ if (datalen + 1 <= sizeof(extra)) { ++ wrqu.data.length = datalen + 1; ++ extra[0] = WLC_E_ACTION_FRAME; ++ memcpy(&extra[1], data, datalen); ++ AP6211_DEBUG("WLC_E_ACTION_FRAME len %d \n", wrqu.data.length); ++ } ++ break; ++ ++ case WLC_E_ACTION_FRAME_COMPLETE: ++ cmd = IWEVCUSTOM; ++ if (sizeof(status) + 1 <= sizeof(extra)) { ++ wrqu.data.length = sizeof(status) + 1; ++ extra[0] = WLC_E_ACTION_FRAME_COMPLETE; ++ memcpy(&extra[1], &status, sizeof(status)); ++ AP6211_DEBUG("wl_iw_event status %d \n", status); ++ } ++ break; ++#endif /* WIRELESS_EXT > 14 */ ++#if WIRELESS_EXT > 17 ++ case WLC_E_MIC_ERROR: { ++ struct iw_michaelmicfailure *micerrevt = (struct iw_michaelmicfailure *)&extra; ++ cmd = IWEVMICHAELMICFAILURE; ++ wrqu.data.length = sizeof(struct iw_michaelmicfailure); ++ if (flags & WLC_EVENT_MSG_GROUP) ++ micerrevt->flags |= IW_MICFAILURE_GROUP; ++ else ++ micerrevt->flags |= IW_MICFAILURE_PAIRWISE; ++ memcpy(micerrevt->src_addr.sa_data, &e->addr, ETHER_ADDR_LEN); ++ micerrevt->src_addr.sa_family = ARPHRD_ETHER; ++ ++ break; ++ } ++ ++ case WLC_E_ASSOC_REQ_IE: ++ cmd = IWEVASSOCREQIE; ++ wrqu.data.length = datalen; ++ if (datalen < sizeof(extra)) ++ memcpy(extra, data, datalen); ++ break; ++ ++ case WLC_E_ASSOC_RESP_IE: ++ cmd = IWEVASSOCRESPIE; ++ wrqu.data.length = datalen; ++ if (datalen < sizeof(extra)) ++ memcpy(extra, data, datalen); ++ break; ++ ++ case WLC_E_PMKID_CACHE: { ++ struct iw_pmkid_cand *iwpmkidcand = (struct iw_pmkid_cand *)&extra; ++ pmkid_cand_list_t *pmkcandlist; ++ pmkid_cand_t *pmkidcand; ++ int count; ++ ++ if (data == NULL) ++ break; ++ ++ cmd = IWEVPMKIDCAND; ++ pmkcandlist = data; ++ count = ntoh32_ua((uint8 *)&pmkcandlist->npmkid_cand); ++ wrqu.data.length = sizeof(struct iw_pmkid_cand); ++ pmkidcand = pmkcandlist->pmkid_cand; ++ while (count) { ++ bzero(iwpmkidcand, sizeof(struct iw_pmkid_cand)); ++ if (pmkidcand->preauth) ++ iwpmkidcand->flags |= IW_PMKID_CAND_PREAUTH; ++ bcopy(&pmkidcand->BSSID, &iwpmkidcand->bssid.sa_data, ++ ETHER_ADDR_LEN); ++ wireless_send_event(dev, cmd, &wrqu, extra); ++ pmkidcand++; ++ count--; ++ } ++ break; ++ } ++#endif /* WIRELESS_EXT > 17 */ ++ ++ case WLC_E_SCAN_COMPLETE: ++#if WIRELESS_EXT > 14 ++ cmd = SIOCGIWSCAN; ++#endif ++ AP6211_DEBUG("event WLC_E_SCAN_COMPLETE\n"); ++ if ((g_iscan) && (g_iscan->sysioc_pid >= 0) && ++ (g_iscan->iscan_state != ISCAN_STATE_IDLE)) ++ up(&g_iscan->sysioc_sem); ++ break; ++ ++ default: ++ /* Cannot translate event */ ++ break; ++ } ++ ++ if (cmd) { ++ if (cmd == SIOCGIWSCAN) ++ wireless_send_event(dev, cmd, &wrqu, NULL); ++ else ++ wireless_send_event(dev, cmd, &wrqu, extra); ++ } ++ ++#if WIRELESS_EXT > 14 ++ /* Look for WLC events that indicate a connection failure. ++ * If found, generate an IWEVCUSTOM event. ++ */ ++ memset(extra, 0, sizeof(extra)); ++ if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) { ++ cmd = IWEVCUSTOM; ++ wrqu.data.length = strlen(extra); ++ wireless_send_event(dev, cmd, &wrqu, extra); ++ } ++#endif /* WIRELESS_EXT > 14 */ ++ ++#endif /* WIRELESS_EXT > 13 */ ++} ++ ++int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats) ++{ ++ int res = 0; ++ wl_cnt_t cnt; ++ int phy_noise; ++ int rssi; ++ scb_val_t scb_val; ++ ++ phy_noise = 0; ++ if ((res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise, sizeof(phy_noise)))) ++ goto done; ++ ++ phy_noise = dtoh32(phy_noise); ++ AP6211_DEBUG("wl_iw_get_wireless_stats phy noise=%d\n *****", phy_noise); ++ ++ scb_val.val = 0; ++ if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)))) ++ goto done; ++ ++ rssi = dtoh32(scb_val.val); ++ AP6211_DEBUG("wl_iw_get_wireless_stats rssi=%d ****** \n", rssi); ++ if (rssi <= WL_IW_RSSI_NO_SIGNAL) ++ wstats->qual.qual = 0; ++ else if (rssi <= WL_IW_RSSI_VERY_LOW) ++ wstats->qual.qual = 1; ++ else if (rssi <= WL_IW_RSSI_LOW) ++ wstats->qual.qual = 2; ++ else if (rssi <= WL_IW_RSSI_GOOD) ++ wstats->qual.qual = 3; ++ else if (rssi <= WL_IW_RSSI_VERY_GOOD) ++ wstats->qual.qual = 4; ++ else ++ wstats->qual.qual = 5; ++ ++ /* Wraps to 0 if RSSI is 0 */ ++ wstats->qual.level = 0x100 + rssi; ++ wstats->qual.noise = 0x100 + phy_noise; ++#if WIRELESS_EXT > 18 ++ wstats->qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM); ++#else ++ wstats->qual.updated |= 7; ++#endif /* WIRELESS_EXT > 18 */ ++ ++#if WIRELESS_EXT > 11 ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters=%d\n *****", (int)sizeof(wl_cnt_t)); ++ ++ memset(&cnt, 0, sizeof(wl_cnt_t)); ++ res = dev_wlc_bufvar_get(dev, "counters", (char *)&cnt, sizeof(wl_cnt_t)); ++ if (res) ++ { ++ AP6211_ERR("wl_iw_get_wireless_stats counters failed error=%d ****** \n", res); ++ goto done; ++ } ++ ++ cnt.version = dtoh16(cnt.version); ++ if (cnt.version != WL_CNT_T_VERSION) { ++ AP6211_DEBUG("\tIncorrect version of counters struct: expected %d; got %d\n", ++ WL_CNT_T_VERSION, cnt.version); ++ goto done; ++ } ++ ++ wstats->discard.nwid = 0; ++ wstats->discard.code = dtoh32(cnt.rxundec); ++ wstats->discard.fragment = dtoh32(cnt.rxfragerr); ++ wstats->discard.retries = dtoh32(cnt.txfail); ++ wstats->discard.misc = dtoh32(cnt.rxrunt) + dtoh32(cnt.rxgiant); ++ wstats->miss.beacon = 0; ++ ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n", ++ dtoh32(cnt.txframe), dtoh32(cnt.txbyte)); ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n", dtoh32(cnt.rxfrmtoolong)); ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters rxbadplcp=%d\n", dtoh32(cnt.rxbadplcp)); ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters rxundec=%d\n", dtoh32(cnt.rxundec)); ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters rxfragerr=%d\n", dtoh32(cnt.rxfragerr)); ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters txfail=%d\n", dtoh32(cnt.txfail)); ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters rxrunt=%d\n", dtoh32(cnt.rxrunt)); ++ AP6211_DEBUG("wl_iw_get_wireless_stats counters rxgiant=%d\n", dtoh32(cnt.rxgiant)); ++ ++#endif /* WIRELESS_EXT > 11 */ ++ ++done: ++ return res; ++} ++ ++static void ++wl_iw_timerfunc(ulong data) ++{ ++ iscan_info_t *iscan = (iscan_info_t *)data; ++ iscan->timer_on = 0; ++ if (iscan->iscan_state != ISCAN_STATE_IDLE) { ++ AP6211_DEBUG("timer trigger\n"); ++ up(&iscan->sysioc_sem); ++ } ++} ++ ++static void ++wl_iw_set_event_mask(struct net_device *dev) ++{ ++ char eventmask[WL_EVENTING_MASK_LEN]; ++ char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ ++ ++ dev_iw_iovar_getbuf(dev, "event_msgs", "", 0, iovbuf, sizeof(iovbuf)); ++ bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); ++ setbit(eventmask, WLC_E_SCAN_COMPLETE); ++ dev_iw_iovar_setbuf(dev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, ++ iovbuf, sizeof(iovbuf)); ++ ++} ++ ++static int ++wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid) ++{ ++ int err = 0; ++ ++ memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); ++ params->bss_type = DOT11_BSSTYPE_ANY; ++ params->scan_type = 0; ++ params->nprobes = -1; ++ params->active_time = -1; ++ params->passive_time = -1; ++ params->home_time = -1; ++ params->channel_num = 0; ++ ++ params->nprobes = htod32(params->nprobes); ++ params->active_time = htod32(params->active_time); ++ params->passive_time = htod32(params->passive_time); ++ params->home_time = htod32(params->home_time); ++ if (ssid && ssid->SSID_len) ++ memcpy(¶ms->ssid, ssid, sizeof(wlc_ssid_t)); ++ ++ return err; ++} ++ ++static int ++wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action) ++{ ++ int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)); ++ wl_iscan_params_t *params; ++ int err = 0; ++ ++ if (ssid && ssid->SSID_len) { ++ params_size += sizeof(wlc_ssid_t); ++ } ++ params = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL); ++ if (params == NULL) { ++ return -ENOMEM; ++ } ++ memset(params, 0, params_size); ++ ASSERT(params_size < WLC_IOCTL_SMLEN); ++ ++ err = wl_iw_iscan_prep(¶ms->params, ssid); ++ ++ if (!err) { ++ params->version = htod32(ISCAN_REQ_VERSION); ++ params->action = htod16(action); ++ params->scan_duration = htod16(0); ++ ++ /* params_size += OFFSETOF(wl_iscan_params_t, params); */ ++ (void) dev_iw_iovar_setbuf(iscan->dev, "iscan", params, params_size, ++ iscan->ioctlbuf, WLC_IOCTL_SMLEN); ++ } ++ ++ kfree(params); ++ return err; ++} ++ ++static uint32 ++wl_iw_iscan_get(iscan_info_t *iscan) ++{ ++ iscan_buf_t * buf; ++ iscan_buf_t * ptr; ++ wl_iscan_results_t * list_buf; ++ wl_iscan_results_t list; ++ wl_scan_results_t *results; ++ uint32 status; ++ ++ /* buffers are allocated on demand */ ++ if (iscan->list_cur) { ++ buf = iscan->list_cur; ++ iscan->list_cur = buf->next; ++ } ++ else { ++ buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL); ++ if (!buf) ++ return WL_SCAN_RESULTS_ABORTED; ++ buf->next = NULL; ++ if (!iscan->list_hdr) ++ iscan->list_hdr = buf; ++ else { ++ ptr = iscan->list_hdr; ++ while (ptr->next) { ++ ptr = ptr->next; ++ } ++ ptr->next = buf; ++ } ++ } ++ memset(buf->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN); ++ list_buf = (wl_iscan_results_t*)buf->iscan_buf; ++ results = &list_buf->results; ++ results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE; ++ results->version = 0; ++ results->count = 0; ++ ++ memset(&list, 0, sizeof(list)); ++ list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN); ++ (void) dev_iw_iovar_getbuf( ++ iscan->dev, ++ "iscanresults", ++ &list, ++ WL_ISCAN_RESULTS_FIXED_SIZE, ++ buf->iscan_buf, ++ WLC_IW_ISCAN_MAXLEN); ++ results->buflen = dtoh32(results->buflen); ++ results->version = dtoh32(results->version); ++ results->count = dtoh32(results->count); ++ AP6211_DEBUG("results->count = %d\n", results->count); ++ ++ AP6211_DEBUG("results->buflen = %d\n", results->buflen); ++ status = dtoh32(list_buf->status); ++ return status; ++} ++ ++static void wl_iw_send_scan_complete(iscan_info_t *iscan) ++{ ++ union iwreq_data wrqu; ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ ++ /* wext expects to get no data for SIOCGIWSCAN Event */ ++ wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL); ++} ++ ++static int ++_iscan_sysioc_thread(void *data) ++{ ++ uint32 status; ++ iscan_info_t *iscan = (iscan_info_t *)data; ++ ++ DAEMONIZE("iscan_sysioc"); ++ ++ status = WL_SCAN_RESULTS_PARTIAL; ++ while (down_interruptible(&iscan->sysioc_sem) == 0) { ++ if (iscan->timer_on) { ++ del_timer(&iscan->timer); ++ iscan->timer_on = 0; ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ rtnl_lock(); ++#endif ++ status = wl_iw_iscan_get(iscan); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ rtnl_unlock(); ++#endif ++ ++ switch (status) { ++ case WL_SCAN_RESULTS_PARTIAL: ++ AP6211_DEBUG("iscanresults incomplete\n"); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ rtnl_lock(); ++#endif ++ /* make sure our buffer size is enough before going next round */ ++ wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ rtnl_unlock(); ++#endif ++ /* Reschedule the timer */ ++ iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms); ++ add_timer(&iscan->timer); ++ iscan->timer_on = 1; ++ break; ++ case WL_SCAN_RESULTS_SUCCESS: ++ AP6211_DEBUG("iscanresults complete\n"); ++ iscan->iscan_state = ISCAN_STATE_IDLE; ++ wl_iw_send_scan_complete(iscan); ++ break; ++ case WL_SCAN_RESULTS_PENDING: ++ AP6211_DEBUG("iscanresults pending\n"); ++ /* Reschedule the timer */ ++ iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms); ++ add_timer(&iscan->timer); ++ iscan->timer_on = 1; ++ break; ++ case WL_SCAN_RESULTS_ABORTED: ++ AP6211_DEBUG("iscanresults aborted\n"); ++ iscan->iscan_state = ISCAN_STATE_IDLE; ++ wl_iw_send_scan_complete(iscan); ++ break; ++ default: ++ AP6211_DEBUG("iscanresults returned unknown status %d\n", status); ++ break; ++ } ++ } ++ complete_and_exit(&iscan->sysioc_exited, 0); ++} ++ ++int ++wl_iw_attach(struct net_device *dev, void * dhdp) ++{ ++ iscan_info_t *iscan = NULL; ++ ++ if (!dev) ++ return 0; ++ ++ iscan = kmalloc(sizeof(iscan_info_t), GFP_KERNEL); ++ if (!iscan) ++ return -ENOMEM; ++ memset(iscan, 0, sizeof(iscan_info_t)); ++ iscan->sysioc_pid = -1; ++ /* we only care about main interface so save a global here */ ++ g_iscan = iscan; ++ iscan->dev = dev; ++ iscan->iscan_state = ISCAN_STATE_IDLE; ++ ++ ++ /* Set up the timer */ ++ iscan->timer_ms = 2000; ++ init_timer(&iscan->timer); ++ iscan->timer.data = (ulong)iscan; ++ iscan->timer.function = wl_iw_timerfunc; ++ ++ sema_init(&iscan->sysioc_sem, 0); ++ init_completion(&iscan->sysioc_exited); ++ iscan->sysioc_pid = kernel_thread(_iscan_sysioc_thread, iscan, 0); ++ if (iscan->sysioc_pid < 0) ++ return -ENOMEM; ++ return 0; ++} ++ ++void wl_iw_detach(void) ++{ ++ iscan_buf_t *buf; ++ iscan_info_t *iscan = g_iscan; ++ if (!iscan) ++ return; ++ if (iscan->sysioc_pid >= 0) { ++ KILL_PROC(iscan->sysioc_pid, SIGTERM); ++ wait_for_completion(&iscan->sysioc_exited); ++ } ++ ++ while (iscan->list_hdr) { ++ buf = iscan->list_hdr->next; ++ kfree(iscan->list_hdr); ++ iscan->list_hdr = buf; ++ } ++ kfree(iscan); ++ g_iscan = NULL; ++} ++ ++#endif /* USE_IW */ +diff --git a/drivers/net/wireless/ap6211/wl_iw.h b/drivers/net/wireless/ap6211/wl_iw.h +new file mode 100755 +index 0000000..c675a56 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_iw.h +@@ -0,0 +1,161 @@ ++/* ++ * Linux Wireless Extensions support ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wl_iw.h 291086 2011-10-21 01:17:24Z $ ++ */ ++ ++#ifndef _wl_iw_h_ ++#define _wl_iw_h_ ++ ++#include ++ ++#include ++#include ++#include ++ ++#define WL_SCAN_PARAMS_SSID_MAX 10 ++#define GET_SSID "SSID=" ++#define GET_CHANNEL "CH=" ++#define GET_NPROBE "NPROBE=" ++#define GET_ACTIVE_ASSOC_DWELL "ACTIVE=" ++#define GET_PASSIVE_ASSOC_DWELL "PASSIVE=" ++#define GET_HOME_DWELL "HOME=" ++#define GET_SCAN_TYPE "TYPE=" ++ ++#define BAND_GET_CMD "GETBAND" ++#define BAND_SET_CMD "SETBAND" ++#define DTIM_SKIP_GET_CMD "DTIMSKIPGET" ++#define DTIM_SKIP_SET_CMD "DTIMSKIPSET" ++#define SETSUSPEND_CMD "SETSUSPENDOPT" ++#define PNOSSIDCLR_SET_CMD "PNOSSIDCLR" ++/* Lin - Is the extra space needed? */ ++#define PNOSETUP_SET_CMD "PNOSETUP " /* TLV command has extra end space */ ++#define PNOENABLE_SET_CMD "PNOFORCE" ++#define PNODEBUG_SET_CMD "PNODEBUG" ++#define TXPOWER_SET_CMD "TXPOWER" ++ ++#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] ++#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" ++ ++/* Structure to keep global parameters */ ++typedef struct wl_iw_extra_params { ++ int target_channel; /* target channel */ ++} wl_iw_extra_params_t; ++ ++struct cntry_locales_custom { ++ char iso_abbrev[WLC_CNTRY_BUF_SZ]; /* ISO 3166-1 country abbreviation */ ++ char custom_locale[WLC_CNTRY_BUF_SZ]; /* Custom firmware locale */ ++ int32 custom_locale_rev; /* Custom local revisin default -1 */ ++}; ++/* ============================================== */ ++/* Defines from wlc_pub.h */ ++#define WL_IW_RSSI_MINVAL -200 /* Low value, e.g. for forcing roam */ ++#define WL_IW_RSSI_NO_SIGNAL -91 /* NDIS RSSI link quality cutoffs */ ++#define WL_IW_RSSI_VERY_LOW -80 /* Very low quality cutoffs */ ++#define WL_IW_RSSI_LOW -70 /* Low quality cutoffs */ ++#define WL_IW_RSSI_GOOD -68 /* Good quality cutoffs */ ++#define WL_IW_RSSI_VERY_GOOD -58 /* Very good quality cutoffs */ ++#define WL_IW_RSSI_EXCELLENT -57 /* Excellent quality cutoffs */ ++#define WL_IW_RSSI_INVALID 0 /* invalid RSSI value */ ++#define MAX_WX_STRING 80 ++#define SSID_FMT_BUF_LEN ((4 * 32) + 1) ++#define isprint(c) bcm_isprint(c) ++#define WL_IW_SET_ACTIVE_SCAN (SIOCIWFIRSTPRIV+1) ++#define WL_IW_GET_RSSI (SIOCIWFIRSTPRIV+3) ++#define WL_IW_SET_PASSIVE_SCAN (SIOCIWFIRSTPRIV+5) ++#define WL_IW_GET_LINK_SPEED (SIOCIWFIRSTPRIV+7) ++#define WL_IW_GET_CURR_MACADDR (SIOCIWFIRSTPRIV+9) ++#define WL_IW_SET_STOP (SIOCIWFIRSTPRIV+11) ++#define WL_IW_SET_START (SIOCIWFIRSTPRIV+13) ++ ++#define G_SCAN_RESULTS 8*1024 ++#define WE_ADD_EVENT_FIX 0x80 ++#define G_WLAN_SET_ON 0 ++#define G_WLAN_SET_OFF 1 ++ ++ ++typedef struct wl_iw { ++ char nickname[IW_ESSID_MAX_SIZE]; ++ ++ struct iw_statistics wstats; ++ ++ int spy_num; ++ uint32 pwsec; /* pairwise wsec setting */ ++ uint32 gwsec; /* group wsec setting */ ++ bool privacy_invoked; /* IW_AUTH_PRIVACY_INVOKED setting */ ++ struct ether_addr spy_addr[IW_MAX_SPY]; ++ struct iw_quality spy_qual[IW_MAX_SPY]; ++ void *wlinfo; ++} wl_iw_t; ++ ++struct wl_ctrl { ++ struct timer_list *timer; ++ struct net_device *dev; ++ long sysioc_pid; ++ struct semaphore sysioc_sem; ++ struct completion sysioc_exited; ++}; ++ ++ ++#if WIRELESS_EXT > 12 ++#include ++extern const struct iw_handler_def wl_iw_handler_def; ++#endif /* WIRELESS_EXT > 12 */ ++ ++extern int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); ++extern void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data); ++extern int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats); ++int wl_iw_attach(struct net_device *dev, void * dhdp); ++int wl_iw_send_priv_event(struct net_device *dev, char *flag); ++ ++void wl_iw_detach(void); ++ ++#define CSCAN_COMMAND "CSCAN " ++#define CSCAN_TLV_PREFIX 'S' ++#define CSCAN_TLV_VERSION 1 ++#define CSCAN_TLV_SUBVERSION 0 ++#define CSCAN_TLV_TYPE_SSID_IE 'S' ++#define CSCAN_TLV_TYPE_CHANNEL_IE 'C' ++#define CSCAN_TLV_TYPE_NPROBE_IE 'N' ++#define CSCAN_TLV_TYPE_ACTIVE_IE 'A' ++#define CSCAN_TLV_TYPE_PASSIVE_IE 'P' ++#define CSCAN_TLV_TYPE_HOME_IE 'H' ++#define CSCAN_TLV_TYPE_STYPE_IE 'T' ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \ ++ iwe_stream_add_event(info, stream, ends, iwe, extra) ++#define IWE_STREAM_ADD_VALUE(info, event, value, ends, iwe, event_len) \ ++ iwe_stream_add_value(info, event, value, ends, iwe, event_len) ++#define IWE_STREAM_ADD_POINT(info, stream, ends, iwe, extra) \ ++ iwe_stream_add_point(info, stream, ends, iwe, extra) ++#else ++#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \ ++ iwe_stream_add_event(stream, ends, iwe, extra) ++#define IWE_STREAM_ADD_VALUE(info, event, value, ends, iwe, event_len) \ ++ iwe_stream_add_value(event, value, ends, iwe, event_len) ++#define IWE_STREAM_ADD_POINT(info, stream, ends, iwe, extra) \ ++ iwe_stream_add_point(stream, ends, iwe, extra) ++#endif ++ ++#endif /* _wl_iw_h_ */ +diff --git a/drivers/net/wireless/ap6211/wl_linux_mon.c b/drivers/net/wireless/ap6211/wl_linux_mon.c +new file mode 100755 +index 0000000..3210664 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wl_linux_mon.c +@@ -0,0 +1,422 @@ ++/* ++ * Broadcom Dongle Host Driver (DHD), Linux monitor network interface ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_linux_mon.c 280623 2011-08-30 14:49:39Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++typedef enum monitor_states ++{ ++ MONITOR_STATE_DEINIT = 0x0, ++ MONITOR_STATE_INIT = 0x1, ++ MONITOR_STATE_INTERFACE_ADDED = 0x2, ++ MONITOR_STATE_INTERFACE_DELETED = 0x4 ++} monitor_states_t; ++int dhd_add_monitor(char *name, struct net_device **new_ndev); ++extern int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); ++int dhd_del_monitor(struct net_device *ndev); ++int dhd_monitor_init(void *dhd_pub); ++int dhd_monitor_uninit(void); ++ ++/** ++ * Local declarations and defintions (not exposed) ++ */ ++#ifndef DHD_MAX_IFS ++#define DHD_MAX_IFS 16 ++#endif ++ ++typedef struct monitor_interface { ++ int radiotap_enabled; ++ struct net_device* real_ndev; /* The real interface that the monitor is on */ ++ struct net_device* mon_ndev; ++} monitor_interface; ++ ++typedef struct dhd_linux_monitor { ++ void *dhd_pub; ++ monitor_states_t monitor_state; ++ monitor_interface mon_if[DHD_MAX_IFS]; ++ struct mutex lock; /* lock to protect mon_if */ ++} dhd_linux_monitor_t; ++ ++static dhd_linux_monitor_t g_monitor; ++ ++static struct net_device* lookup_real_netdev(char *name); ++static monitor_interface* ndev_to_monif(struct net_device *ndev); ++static int dhd_mon_if_open(struct net_device *ndev); ++static int dhd_mon_if_stop(struct net_device *ndev); ++static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev); ++static void dhd_mon_if_set_multicast_list(struct net_device *ndev); ++static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr); ++ ++static const struct net_device_ops dhd_mon_if_ops = { ++ .ndo_open = dhd_mon_if_open, ++ .ndo_stop = dhd_mon_if_stop, ++ .ndo_start_xmit = dhd_mon_if_subif_start_xmit, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) ++ .ndo_set_rx_mode = dhd_mon_if_set_multicast_list, ++#else ++ .ndo_set_multicast_list = dhd_mon_if_set_multicast_list, ++#endif ++ .ndo_set_mac_address = dhd_mon_if_change_mac, ++}; ++ ++/** ++ * Local static function defintions ++ */ ++ ++/* Look up dhd's net device table to find a match (e.g. interface "eth0" is a match for "mon.eth0" ++ * "p2p-eth0-0" is a match for "mon.p2p-eth0-0") ++ */ ++static struct net_device* lookup_real_netdev(char *name) ++{ ++ struct net_device *ndev_found = NULL; ++ ++ int i; ++ int len = 0; ++ int last_name_len = 0; ++ struct net_device *ndev; ++ ++ /* We need to find interface "p2p-p2p-0" corresponding to monitor interface "mon-p2p-0", ++ * Once mon iface name reaches IFNAMSIZ, it is reset to p2p0-0 and corresponding mon ++ * iface would be mon-p2p0-0. ++ */ ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ ndev = dhd_idx2net(g_monitor.dhd_pub, i); ++ ++ /* Skip "p2p" and look for "-p2p0-x" in monitor interface name. If it ++ * it matches, then this netdev is the corresponding real_netdev. ++ */ ++ if (ndev && strstr(ndev->name, "p2p-p2p0")) { ++ len = strlen("p2p"); ++ } else { ++ /* if p2p- is not present, then the IFNAMSIZ have reached and name ++ * would have got reset. In this casse,look for p2p0-x in mon-p2p0-x ++ */ ++ len = 0; ++ } ++ if (ndev && strstr(name, (ndev->name + len))) { ++ if (strlen(ndev->name) > last_name_len) { ++ ndev_found = ndev; ++ last_name_len = strlen(ndev->name); ++ } ++ } ++ } ++ ++ return ndev_found; ++} ++ ++static monitor_interface* ndev_to_monif(struct net_device *ndev) ++{ ++ int i; ++ ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ if (g_monitor.mon_if[i].mon_ndev == ndev) ++ return &g_monitor.mon_if[i]; ++ } ++ ++ return NULL; ++} ++ ++static int dhd_mon_if_open(struct net_device *ndev) ++{ ++ int ret = 0; ++ ++ AP6211_DEBUG("enter\n"); ++ return ret; ++} ++ ++static int dhd_mon_if_stop(struct net_device *ndev) ++{ ++ int ret = 0; ++ ++ AP6211_DEBUG("enter\n"); ++ return ret; ++} ++ ++static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev) ++{ ++ int ret = 0; ++ int rtap_len; ++ int qos_len = 0; ++ int dot11_hdr_len = 24; ++ int snap_len = 6; ++ unsigned char *pdata; ++ unsigned short frame_ctl; ++ unsigned char src_mac_addr[6]; ++ unsigned char dst_mac_addr[6]; ++ struct ieee80211_hdr *dot11_hdr; ++ struct ieee80211_radiotap_header *rtap_hdr; ++ monitor_interface* mon_if; ++ ++ AP6211_DEBUG("enter\n"); ++ ++ mon_if = ndev_to_monif(ndev); ++ if (mon_if == NULL || mon_if->real_ndev == NULL) { ++ AP6211_DEBUG(" cannot find matched net dev, skip the packet\n"); ++ goto fail; ++ } ++ ++ if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) ++ goto fail; ++ ++ rtap_hdr = (struct ieee80211_radiotap_header *)skb->data; ++ if (unlikely(rtap_hdr->it_version)) ++ goto fail; ++ ++ rtap_len = ieee80211_get_radiotap_len(skb->data); ++ if (unlikely(skb->len < rtap_len)) ++ goto fail; ++ ++ AP6211_DEBUG("radiotap len (should be 14): %d\n", rtap_len); ++ ++ /* Skip the ratio tap header */ ++ skb_pull(skb, rtap_len); ++ ++ dot11_hdr = (struct ieee80211_hdr *)skb->data; ++ frame_ctl = le16_to_cpu(dot11_hdr->frame_control); ++ /* Check if the QoS bit is set */ ++ if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { ++ /* Check if this ia a Wireless Distribution System (WDS) frame ++ * which has 4 MAC addresses ++ */ ++ if (dot11_hdr->frame_control & 0x0080) ++ qos_len = 2; ++ if ((dot11_hdr->frame_control & 0x0300) == 0x0300) ++ dot11_hdr_len += 6; ++ ++ memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr)); ++ memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr)); ++ ++ /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for ++ * for two MAC addresses ++ */ ++ skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2); ++ pdata = (unsigned char*)skb->data; ++ memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr)); ++ memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr)); ++ PKTSETPRIO(skb, 0); ++ ++ AP6211_DEBUG("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name); ++ ++ /* Use the real net device to transmit the packet */ ++ ret = dhd_start_xmit(skb, mon_if->real_ndev); ++ ++ return ret; ++ } ++fail: ++ dev_kfree_skb(skb); ++ return 0; ++} ++ ++static void dhd_mon_if_set_multicast_list(struct net_device *ndev) ++{ ++ monitor_interface* mon_if; ++ ++ mon_if = ndev_to_monif(ndev); ++ if (mon_if == NULL || mon_if->real_ndev == NULL) { ++ AP6211_DEBUG(" cannot find matched net dev, skip the packet\n"); ++ } else { ++ AP6211_DEBUG("enter, if name: %s, matched if name %s\n", ++ ndev->name, mon_if->real_ndev->name); ++ } ++} ++ ++static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr) ++{ ++ int ret = 0; ++ monitor_interface* mon_if; ++ ++ mon_if = ndev_to_monif(ndev); ++ if (mon_if == NULL || mon_if->real_ndev == NULL) { ++ AP6211_DEBUG(" cannot find matched net dev, skip the packet\n"); ++ } else { ++ AP6211_DEBUG("enter, if name: %s, matched if name %s\n", ++ ndev->name, mon_if->real_ndev->name); ++ } ++ return ret; ++} ++ ++/** ++ * Global function definitions (declared in dhd_linux_mon.h) ++ */ ++ ++int dhd_add_monitor(char *name, struct net_device **new_ndev) ++{ ++ int i; ++ int idx = -1; ++ int ret = 0; ++ struct net_device* ndev = NULL; ++ dhd_linux_monitor_t **dhd_mon; ++ ++ mutex_lock(&g_monitor.lock); ++ ++ AP6211_DEBUG("enter, if name: %s\n", name); ++ if (!name || !new_ndev) { ++ AP6211_DEBUG("invalid parameters\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* ++ * Find a vacancy ++ */ ++ for (i = 0; i < DHD_MAX_IFS; i++) ++ if (g_monitor.mon_if[i].mon_ndev == NULL) { ++ idx = i; ++ break; ++ } ++ if (idx == -1) { ++ AP6211_DEBUG("exceeds maximum interfaces\n"); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ndev = alloc_etherdev(sizeof(dhd_linux_monitor_t*)); ++ if (!ndev) { ++ AP6211_DEBUG("failed to allocate memory\n"); ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ndev->type = ARPHRD_IEEE80211_RADIOTAP; ++ strncpy(ndev->name, name, IFNAMSIZ); ++ ndev->name[IFNAMSIZ - 1] = 0; ++ ndev->netdev_ops = &dhd_mon_if_ops; ++ ++ ret = register_netdevice(ndev); ++ if (ret) { ++ AP6211_DEBUG(" register_netdevice failed (%d)\n", ret); ++ goto out; ++ } ++ ++ *new_ndev = ndev; ++ g_monitor.mon_if[idx].radiotap_enabled = TRUE; ++ g_monitor.mon_if[idx].mon_ndev = ndev; ++ g_monitor.mon_if[idx].real_ndev = lookup_real_netdev(name); ++ dhd_mon = (dhd_linux_monitor_t **)netdev_priv(ndev); ++ *dhd_mon = &g_monitor; ++ g_monitor.monitor_state = MONITOR_STATE_INTERFACE_ADDED; ++ AP6211_DEBUG("net device returned: 0x%p\n", ndev); ++ AP6211_DEBUG("found a matched net device, name %s\n", g_monitor.mon_if[idx].real_ndev->name); ++ ++out: ++ if (ret && ndev) ++ free_netdev(ndev); ++ ++ mutex_unlock(&g_monitor.lock); ++ return ret; ++ ++} ++ ++int dhd_del_monitor(struct net_device *ndev) ++{ ++ int i; ++ bool rollback_lock = false; ++ if (!ndev) ++ return -EINVAL; ++ mutex_lock(&g_monitor.lock); ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ if (g_monitor.mon_if[i].mon_ndev == ndev || ++ g_monitor.mon_if[i].real_ndev == ndev) { ++ g_monitor.mon_if[i].real_ndev = NULL; ++ if (rtnl_is_locked()) { ++ rtnl_unlock(); ++ rollback_lock = true; ++ } ++ unregister_netdev(g_monitor.mon_if[i].mon_ndev); ++ free_netdev(g_monitor.mon_if[i].mon_ndev); ++ g_monitor.mon_if[i].mon_ndev = NULL; ++ g_monitor.monitor_state = MONITOR_STATE_INTERFACE_DELETED; ++ break; ++ } ++ } ++ if (rollback_lock) { ++ rtnl_lock(); ++ rollback_lock = false; ++ } ++ ++ if (g_monitor.monitor_state != ++ MONITOR_STATE_INTERFACE_DELETED) ++ AP6211_DEBUG("interface not found in monitor IF array, is this a monitor IF? 0x%p\n", ++ ndev); ++ mutex_unlock(&g_monitor.lock); ++ ++ return 0; ++} ++ ++int dhd_monitor_init(void *dhd_pub) ++{ ++ if (g_monitor.monitor_state == MONITOR_STATE_DEINIT) { ++ g_monitor.dhd_pub = dhd_pub; ++ mutex_init(&g_monitor.lock); ++ g_monitor.monitor_state = MONITOR_STATE_INIT; ++ } ++ return 0; ++} ++ ++int dhd_monitor_uninit(void) ++{ ++ int i; ++ struct net_device *ndev; ++ bool rollback_lock = false; ++ mutex_lock(&g_monitor.lock); ++ if (g_monitor.monitor_state != MONITOR_STATE_DEINIT) { ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ ndev = g_monitor.mon_if[i].mon_ndev; ++ if (ndev) { ++ if (rtnl_is_locked()) { ++ rtnl_unlock(); ++ rollback_lock = true; ++ } ++ unregister_netdev(ndev); ++ free_netdev(ndev); ++ g_monitor.mon_if[i].real_ndev = NULL; ++ g_monitor.mon_if[i].mon_ndev = NULL; ++ if (rollback_lock) { ++ rtnl_lock(); ++ rollback_lock = false; ++ } ++ } ++ } ++ g_monitor.monitor_state = MONITOR_STATE_DEINIT; ++ } ++ mutex_unlock(&g_monitor.lock); ++ return 0; ++} +diff --git a/drivers/net/wireless/ap6211/wldev_common.c b/drivers/net/wireless/ap6211/wldev_common.c +new file mode 100755 +index 0000000..596e448 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wldev_common.c +@@ -0,0 +1,374 @@ ++/* ++ * Common function shared by Linux WEXT, cfg80211 and p2p drivers ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wldev_common.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 $ ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++ ++#define htod32(i) i ++#define htod16(i) i ++#define dtoh32(i) i ++#define dtoh16(i) i ++#define htodchanspec(i) i ++#define dtohchanspec(i) i ++ ++extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd); ++ ++s32 wldev_ioctl( ++ struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set) ++{ ++ s32 ret = 0; ++ struct wl_ioctl ioc; ++ ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ioc.cmd = cmd; ++ ioc.buf = arg; ++ ioc.len = len; ++ ioc.set = set; ++ ++ ret = dhd_ioctl_entry_local(dev, &ioc, cmd); ++ ++ return ret; ++} ++ ++/* Format a iovar buffer, not bsscfg indexed. The bsscfg index will be ++ * taken care of in dhd_ioctl_entry. Internal use only, not exposed to ++ * wl_iw, wl_cfg80211 and wl_cfgp2p ++ */ ++static s32 wldev_mkiovar( ++ s8 *iovar_name, s8 *param, s32 paramlen, ++ s8 *iovar_buf, u32 buflen) ++{ ++ s32 iolen = 0; ++ ++ iolen = bcm_mkiovar(iovar_name, param, paramlen, iovar_buf, buflen); ++ return iolen; ++} ++ ++s32 wldev_iovar_getbuf( ++ struct net_device *dev, s8 *iovar_name, ++ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) ++{ ++ s32 ret = 0; ++ if (buf_sync) { ++ mutex_lock(buf_sync); ++ } ++ wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); ++ ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE); ++ if (buf_sync) ++ mutex_unlock(buf_sync); ++ return ret; ++} ++ ++ ++s32 wldev_iovar_setbuf( ++ struct net_device *dev, s8 *iovar_name, ++ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) ++{ ++ s32 ret = 0; ++ s32 iovar_len; ++ if (buf_sync) { ++ mutex_lock(buf_sync); ++ } ++ iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); ++ if (iovar_len > 0) ++ ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); ++ else ++ ret = BCME_BUFTOOSHORT; ++ if (buf_sync) ++ mutex_unlock(buf_sync); ++ return ret; ++} ++ ++s32 wldev_iovar_setint( ++ struct net_device *dev, s8 *iovar, s32 val) ++{ ++ s8 iovar_buf[WLC_IOCTL_SMLEN]; ++ ++ val = htod32(val); ++ memset(iovar_buf, 0, sizeof(iovar_buf)); ++ return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf, ++ sizeof(iovar_buf), NULL); ++} ++ ++ ++s32 wldev_iovar_getint( ++ struct net_device *dev, s8 *iovar, s32 *pval) ++{ ++ s8 iovar_buf[WLC_IOCTL_SMLEN]; ++ s32 err; ++ ++ memset(iovar_buf, 0, sizeof(iovar_buf)); ++ err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf, ++ sizeof(iovar_buf), NULL); ++ if (err == 0) ++ { ++ memcpy(pval, iovar_buf, sizeof(*pval)); ++ *pval = dtoh32(*pval); ++ } ++ return err; ++} ++ ++/** Format a bsscfg indexed iovar buffer. The bsscfg index will be ++ * taken care of in dhd_ioctl_entry. Internal use only, not exposed to ++ * wl_iw, wl_cfg80211 and wl_cfgp2p ++ */ ++s32 wldev_mkiovar_bsscfg( ++ const s8 *iovar_name, s8 *param, s32 paramlen, ++ s8 *iovar_buf, s32 buflen, s32 bssidx) ++{ ++ const s8 *prefix = "bsscfg:"; ++ s8 *p; ++ u32 prefixlen; ++ u32 namelen; ++ u32 iolen; ++ ++ if (bssidx == 0) { ++ return wldev_mkiovar((s8*)iovar_name, (s8 *)param, paramlen, ++ (s8 *) iovar_buf, buflen); ++ } ++ ++ prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */ ++ namelen = (u32) strlen(iovar_name) + 1; /* lengh of iovar name + null */ ++ iolen = prefixlen + namelen + sizeof(u32) + paramlen; ++ ++ if (buflen < 0 || iolen > (u32)buflen) ++ { ++ AP6211_ERR("%s: buffer is too short\n", __FUNCTION__); ++ return BCME_BUFTOOSHORT; ++ } ++ ++ p = (s8 *)iovar_buf; ++ ++ /* copy prefix, no null */ ++ memcpy(p, prefix, prefixlen); ++ p += prefixlen; ++ ++ /* copy iovar name including null */ ++ memcpy(p, iovar_name, namelen); ++ p += namelen; ++ ++ /* bss config index as first param */ ++ bssidx = htod32(bssidx); ++ memcpy(p, &bssidx, sizeof(u32)); ++ p += sizeof(u32); ++ ++ /* parameter buffer follows */ ++ if (paramlen) ++ memcpy(p, param, paramlen); ++ ++ return iolen; ++ ++} ++ ++s32 wldev_iovar_getbuf_bsscfg( ++ struct net_device *dev, s8 *iovar_name, ++ void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) ++{ ++ s32 ret = 0; ++ if (buf_sync) { ++ mutex_lock(buf_sync); ++ } ++ ++ wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); ++ ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE); ++ if (buf_sync) { ++ mutex_unlock(buf_sync); ++ } ++ return ret; ++ ++} ++ ++s32 wldev_iovar_setbuf_bsscfg( ++ struct net_device *dev, s8 *iovar_name, ++ void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) ++{ ++ s32 ret = 0; ++ s32 iovar_len; ++ if (buf_sync) { ++ mutex_lock(buf_sync); ++ } ++ iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); ++ if (iovar_len > 0) ++ ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); ++ else { ++ ret = BCME_BUFTOOSHORT; ++ } ++ ++ if (buf_sync) { ++ mutex_unlock(buf_sync); ++ } ++ return ret; ++} ++ ++s32 wldev_iovar_setint_bsscfg( ++ struct net_device *dev, s8 *iovar, s32 val, s32 bssidx) ++{ ++ s8 iovar_buf[WLC_IOCTL_SMLEN]; ++ ++ val = htod32(val); ++ memset(iovar_buf, 0, sizeof(iovar_buf)); ++ return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf, ++ sizeof(iovar_buf), bssidx, NULL); ++} ++ ++ ++s32 wldev_iovar_getint_bsscfg( ++ struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx) ++{ ++ s8 iovar_buf[WLC_IOCTL_SMLEN]; ++ s32 err; ++ ++ memset(iovar_buf, 0, sizeof(iovar_buf)); ++ err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf, ++ sizeof(iovar_buf), bssidx, NULL); ++ if (err == 0) ++ { ++ memcpy(pval, iovar_buf, sizeof(*pval)); ++ *pval = dtoh32(*pval); ++ } ++ return err; ++} ++ ++int wldev_get_link_speed( ++ struct net_device *dev, int *plink_speed) ++{ ++ int error; ++ ++ if (!plink_speed) ++ return -ENOMEM; ++ error = wldev_ioctl(dev, WLC_GET_RATE, plink_speed, sizeof(int), 0); ++ if (unlikely(error)) ++ return error; ++ ++ /* Convert internal 500Kbps to Kbps */ ++ *plink_speed *= 500; ++ return error; ++} ++ ++int wldev_get_rssi( ++ struct net_device *dev, int *prssi) ++{ ++ scb_val_t scb_val; ++ int error; ++ ++ if (!prssi) ++ return -ENOMEM; ++ bzero(&scb_val, sizeof(scb_val_t)); ++ ++ error = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0); ++ if (unlikely(error)) ++ return error; ++ ++ *prssi = dtoh32(scb_val.val); ++ return error; ++} ++ ++int wldev_get_ssid( ++ struct net_device *dev, wlc_ssid_t *pssid) ++{ ++ int error; ++ ++ if (!pssid) ++ return -ENOMEM; ++ error = wldev_ioctl(dev, WLC_GET_SSID, pssid, sizeof(wlc_ssid_t), 0); ++ if (unlikely(error)) ++ return error; ++ pssid->SSID_len = dtoh32(pssid->SSID_len); ++ return error; ++} ++ ++int wldev_get_band( ++ struct net_device *dev, uint *pband) ++{ ++ int error; ++ ++ error = wldev_ioctl(dev, WLC_GET_BAND, pband, sizeof(uint), 0); ++ return error; ++} ++ ++int wldev_set_band( ++ struct net_device *dev, uint band) ++{ ++ int error = -1; ++ ++ if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) { ++ error = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true); ++ if (!error) ++ dhd_bus_band_set(dev, band); ++ } ++ return error; ++} ++ ++int wldev_set_country( ++ struct net_device *dev, char *country_code) ++{ ++ int error = -1; ++ wl_country_t cspec = {{0}, 0, {0}}; ++ scb_val_t scbval; ++ char smbuf[WLC_IOCTL_SMLEN]; ++ ++ if (!country_code) ++ return error; ++ ++ error = wldev_iovar_getbuf(dev, "country", &cspec, sizeof(cspec), ++ smbuf, sizeof(smbuf), NULL); ++ if (error < 0) ++ AP6211_ERR("%s: get country failed = %d\n", __FUNCTION__, error); ++ ++ if ((error < 0) || ++ (strncmp(country_code, smbuf, WLC_CNTRY_BUF_SZ) != 0)) { ++ bzero(&scbval, sizeof(scb_val_t)); ++ error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); ++ if (error < 0) { ++ AP6211_ERR("%s: set country failed due to Disassoc error %d\n", ++ __FUNCTION__, error); ++ return error; ++ } ++ cspec.rev = -1; ++ memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ); ++ memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ); ++ get_customized_country_code((char *)&cspec.country_abbrev, &cspec); ++ error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec), ++ smbuf, sizeof(smbuf), NULL); ++ if (error < 0) { ++ AP6211_ERR("%s: set country for %s as %s rev %d failed\n", ++ __FUNCTION__, country_code, cspec.ccode, cspec.rev); ++ return error; ++ } ++ dhd_bus_country_set(dev, &cspec); ++ AP6211_ERR("%s: set country for %s as %s rev %d\n", ++ __FUNCTION__, country_code, cspec.ccode, cspec.rev); ++ } ++ return 0; ++} +diff --git a/drivers/net/wireless/ap6211/wldev_common.h b/drivers/net/wireless/ap6211/wldev_common.h +new file mode 100755 +index 0000000..f9bf425 +--- /dev/null ++++ b/drivers/net/wireless/ap6211/wldev_common.h +@@ -0,0 +1,111 @@ ++/* ++ * Common function shared by Linux WEXT, cfg80211 and p2p drivers ++ * ++ * Copyright (C) 1999-2012, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: wldev_common.h,v 1.1.4.1.2.14 2011-02-09 01:40:07 $ ++ */ ++#ifndef __WLDEV_COMMON_H__ ++#define __WLDEV_COMMON_H__ ++ ++#include ++ ++/* wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or ++ * netdev_ops->ndo_do_ioctl in new kernels) ++ * @dev: the net_device handle ++ */ ++s32 wldev_ioctl( ++ struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set); ++ ++/** Retrieve named IOVARs, this function calls wl_dev_ioctl with ++ * WLC_GET_VAR IOCTL code ++ */ ++s32 wldev_iovar_getbuf( ++ struct net_device *dev, s8 *iovar_name, ++ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync); ++ ++/** Set named IOVARs, this function calls wl_dev_ioctl with ++ * WLC_SET_VAR IOCTL code ++ */ ++s32 wldev_iovar_setbuf( ++ struct net_device *dev, s8 *iovar_name, ++ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync); ++ ++s32 wldev_iovar_setint( ++ struct net_device *dev, s8 *iovar, s32 val); ++ ++s32 wldev_iovar_getint( ++ struct net_device *dev, s8 *iovar, s32 *pval); ++ ++/** The following function can be implemented if there is a need for bsscfg ++ * indexed IOVARs ++ */ ++ ++s32 wldev_mkiovar_bsscfg( ++ const s8 *iovar_name, s8 *param, s32 paramlen, ++ s8 *iovar_buf, s32 buflen, s32 bssidx); ++ ++/** Retrieve named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with ++ * WLC_GET_VAR IOCTL code ++ */ ++s32 wldev_iovar_getbuf_bsscfg( ++ struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, ++ void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); ++ ++/** Set named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with ++ * WLC_SET_VAR IOCTL code ++ */ ++s32 wldev_iovar_setbuf_bsscfg( ++ struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, ++ void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); ++ ++s32 wldev_iovar_getint_bsscfg( ++ struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx); ++ ++s32 wldev_iovar_setint_bsscfg( ++ struct net_device *dev, s8 *iovar, s32 val, s32 bssidx); ++ ++extern void get_customized_country_code(char *country_iso_code, wl_country_t *cspec); ++extern void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec); ++extern void dhd_bus_band_set(struct net_device *dev, uint band); ++extern int wldev_set_country(struct net_device *dev, char *country_code); ++extern int net_os_wake_lock(struct net_device *dev); ++extern int net_os_wake_unlock(struct net_device *dev); ++extern int net_os_wake_lock_timeout(struct net_device *dev); ++extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val); ++extern int net_os_set_dtim_skip(struct net_device *dev, int val); ++extern int net_os_set_suspend_disable(struct net_device *dev, int val); ++extern int net_os_set_suspend(struct net_device *dev, int val, int force); ++extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, ++ int max, int *bytes_left); ++ ++/* Get the link speed from dongle, speed is in kpbs */ ++int wldev_get_link_speed(struct net_device *dev, int *plink_speed); ++ ++int wldev_get_rssi(struct net_device *dev, int *prssi); ++ ++int wldev_get_ssid(struct net_device *dev, wlc_ssid_t *pssid); ++ ++int wldev_get_band(struct net_device *dev, uint *pband); ++ ++int wldev_set_band(struct net_device *dev, uint band); ++ ++#endif /* __WLDEV_COMMON_H__ */ +-- +1.9.1 + From 33eec55dd4bac321cd48c69735af7143c067bc36 Mon Sep 17 00:00:00 2001 From: Thomas Kaiser Date: Mon, 29 Feb 2016 16:13:15 +0100 Subject: [PATCH 10/15] Prepare Pine64 addition and Ubuntu Xenial changes --- scripts/armhwinfo | 8 ++++++++ scripts/firstrun | 15 +++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/scripts/armhwinfo b/scripts/armhwinfo index bd05db902b..85794f2992 100644 --- a/scripts/armhwinfo +++ b/scripts/armhwinfo @@ -173,6 +173,14 @@ if [ "$ARCH" = "armv7l" ]; then create_motd_warning "It seems the image is running on ${ID} but you're using wrong settings: ${ScriptBinUsed##*/}" fi fi +elif [ "$ARCH" = "aarch64" ]; then + if [ $HARDWARE = "sun50iw1p1" ]; then + if [ $MEMTOTAL -gt 600 ]; then + ID="Pine64+" + else + ID="Pine64" + fi + fi fi [ -f /proc/device-tree/model ] && read MACHINE /dev/null 2>&1 || exit 1 + done +} # check_prerequisits + main() { + check_prerequisits collect_informations display_alert "Force password change upon first login" chage -d 0 root @@ -185,4 +193,3 @@ main() { main exit 0 - From 4ec85dfafd9778baa7bd73503e087184276655bf Mon Sep 17 00:00:00 2001 From: Thomas Kaiser Date: Mon, 29 Feb 2016 20:25:50 +0100 Subject: [PATCH 11/15] Add extended/continuous logging to armhwinfo. Enhanced user documentation regarding locale --- documentation/user-faq.md | 5 ++++- scripts/armhwinfo | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/documentation/user-faq.md b/documentation/user-faq.md index 99bb2b733c..201694e04c 100644 --- a/documentation/user-faq.md +++ b/documentation/user-faq.md @@ -156,9 +156,12 @@ keyboard: dpkg-reconfigure keyboard-configuration -system language: +system language: + # Debian --> https://wiki.debian.org/ChangeLanguage dpkg-reconfigure locales + # Ubuntu --> https://help.ubuntu.com/community/Locale + update-locale LANG=[options] && dpkg-reconfigure locales console font, codepage: diff --git a/scripts/armhwinfo b/scripts/armhwinfo index 85794f2992..891ab7de47 100644 --- a/scripts/armhwinfo +++ b/scripts/armhwinfo @@ -13,6 +13,8 @@ if [ "X$1" != "Xstart" ]; then exit 1 fi +export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + create_motd_warning() { cat > /etc/update-motd.d/90-warning < /var/run/machine.id export HARDWARE DISTROID DISTROCODE ARCH KERNELID MACHINE ID + +echo -e "\n\n\n$(date) $HARDWARE $DISTROID $DISTROCODE $ARCH $KERNELID $MACHINE $ID" >>/var/log/armhwinfo.log +cat /proc/version >>/var/log/armhwinfo.log +cat "${TMPFILE}" >>/var/log/armhwinfo.log +lsusb -v >>/var/log/armhwinfo.log +lscpu >>/var/log/armhwinfo.log +cat /proc/cpuinfo >>/var/log/armhwinfo.log +cat /proc/meminfo >>/var/log/armhwinfo.log +cat /proc/interrupts >>/var/log/armhwinfo.log +ifconfig >>/var/log/armhwinfo.log +df -h >>/var/log/armhwinfo.log From 493507f3c90f7bbd58e19c9196c6a58aabdd0278 Mon Sep 17 00:00:00 2001 From: Igor Pecovnik Date: Mon, 29 Feb 2016 20:36:28 +0100 Subject: [PATCH 12/15] Banana PRO leds corrections, default choose PRO model, added to armhwinfo --- config/bananapipro.fex | 5 +---- configuration.sh | 2 +- scripts/armhwinfo | 3 +++ scripts/firstrun | 9 +++++++++ 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/config/bananapipro.fex b/config/bananapipro.fex index 3bf50f461b..275521be59 100644 --- a/config/bananapipro.fex +++ b/config/bananapipro.fex @@ -971,11 +971,8 @@ switch_used = 0 leds_used = 1 leds_num = 2 leds_pin_1 = port:PH24<1><0> -leds_pin_2 = port:PG02<1><0> leds_name_1 = "green:ph24:led1" -leds_name_2 = "blue:pg02:led2" -leds_trigger_1 = "heartbeat" -leds_trigger_2 = "mmc0" +leds_trigger_1 = "mmc0" [ir_para] ir_used = 1 diff --git a/configuration.sh b/configuration.sh index 97380073d4..dc9531427c 100644 --- a/configuration.sh +++ b/configuration.sh @@ -179,7 +179,7 @@ case $BOARD in #build 6 LINUXFAMILY="sun7i" BOOTCONFIG="Bananapi_defconfig" - MODULES="hci_uart gpio_sunxi rfcomm hidp sunxi-ir bonding spi_sun7i 8021q a20_tp ap6211" + MODULES="hci_uart gpio_sunxi rfcomm hidp sunxi-ir bonding spi_sun7i 8021q a20_tp #ap6211" MODULES_NEXT="brcmfmac bonding" DESKTOP_TARGET="trusty,%" ;; diff --git a/scripts/armhwinfo b/scripts/armhwinfo index bd05db902b..5c8212470f 100644 --- a/scripts/armhwinfo +++ b/scripts/armhwinfo @@ -39,6 +39,7 @@ TERMINUS=$(lsusb | grep "1a40:0101") SWITCH=$(grep "BCM53125" "${TMPFILE}") INTERUPT=$(grep "eth0" /proc/interrupts) WIFI8189ES=$(lsmod | grep 8189es | grep -v "0 $" | grep -v "0$") # ignore when not loaded +WIFIAP6211=$(lsmod | grep ap6211) for i in $( lsblk -idn -o NAME ); do read ROTATE /dev/null 2>&1 sed -i 's/allow-hotplug\ eth0/auto eth0/' /etc/network/interfaces.default } # main From f5ebec1f77e1073bd2d98a7dfd45101807e3550e Mon Sep 17 00:00:00 2001 From: Thomas Kaiser Date: Mon, 29 Feb 2016 22:10:04 +0100 Subject: [PATCH 13/15] Fixed OPi 2 auto detection with ugly hack, extended armhwinfo's logging --- scripts/armhwinfo | 15 ++++++++++++++- scripts/firstrun | 17 +++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/scripts/armhwinfo b/scripts/armhwinfo index 891ab7de47..cb0c056ce5 100644 --- a/scripts/armhwinfo +++ b/scripts/armhwinfo @@ -203,13 +203,26 @@ echo -e "[\e[0;32m ok \x1B[0m] Starting ARM hardware info: $ID" echo $ID > /var/run/machine.id export HARDWARE DISTROID DISTROCODE ARCH KERNELID MACHINE ID -echo -e "\n\n\n$(date) $HARDWARE $DISTROID $DISTROCODE $ARCH $KERNELID $MACHINE $ID" >>/var/log/armhwinfo.log +if [ -f /var/log/armhwinfo.log ]; then + echo -e "\n\n\n$(date) $HARDWARE $DISTROID $DISTROCODE $ARCH $KERNELID $MACHINE $ID" >>/var/log/armhwinfo.log +else + echo "$(date) $HARDWARE $DISTROID $DISTROCODE $ARCH $KERNELID $MACHINE $ID" >>/var/log/armhwinfo.log + chmod 755 /var/log/armhwinfo.log +fi cat /proc/version >>/var/log/armhwinfo.log +echo -e "\n### dmesg:\n" >>/var/log/armhwinfo.log cat "${TMPFILE}" >>/var/log/armhwinfo.log +echo -e "\n### lsusb:" >>/var/log/armhwinfo.log lsusb -v >>/var/log/armhwinfo.log +echo -e "\n### lscpu:\n" >>/var/log/armhwinfo.log lscpu >>/var/log/armhwinfo.log +echo -e "\n### cpuinfo:\n" >>/var/log/armhwinfo.log cat /proc/cpuinfo >>/var/log/armhwinfo.log +echo -e "\n### meminfo:\n" >>/var/log/armhwinfo.log cat /proc/meminfo >>/var/log/armhwinfo.log +echo -e "\n### interrupts:\n" >>/var/log/armhwinfo.log cat /proc/interrupts >>/var/log/armhwinfo.log +echo -e "\n### ifconfig:\n" >>/var/log/armhwinfo.log ifconfig >>/var/log/armhwinfo.log +echo -e "\n### df:\n" >>/var/log/armhwinfo.log df -h >>/var/log/armhwinfo.log diff --git a/scripts/firstrun b/scripts/firstrun index d5796a733a..944bd02d6d 100644 --- a/scripts/firstrun +++ b/scripts/firstrun @@ -112,9 +112,16 @@ autodetect_h3() { # wait for armhwinfo sleep 3 MACHINE="$(tail -n1 /run/machine.id)" + NEWHOSTNAME="$(echo "${MACHINE}" | tr '[:upper:]' '[:lower:]' | sed -e 's/+/plus/' -e 's/\ //g')" + ScriptBinName="$(echo "${NEWHOSTNAME}" | sed -e 's/2mini$/2/g' -e 's/plus2$/plus/g').bin" + ScriptBinUsed="$(readlink -f "/boot/script.bin")" case ${MACHINE} in "Orange Pi+"*) - ln -sf /boot/bin/orangepiplus.bin /boot/script.bin + if [ "X${ScriptBinName}" != "X${ScriptBinUsed##*/}" ]; then + # wrong detection due to disabled Ethernet on 1st boot + ln -sf /boot/bin/orangepi2.bin /boot/script.bin + NEWHOSTNAME="orangepi2" + fi ;; "Orange Pi 2"*) ln -sf /boot/bin/orangepi2.bin /boot/script.bin @@ -132,8 +139,14 @@ autodetect_h3() { sed -i -e 's/MIN_SPEED=480000/MIN_SPEED=648000/' \ -e 's/MAX_SPEED=1296000/MAX_SPEED=1200000/' /etc/default/cpufrequtils ;; + "Banana Pi M2+") + if [ "X${ScriptBinName}" != "X${ScriptBinUsed##*/}" ]; then + # wrong detection due to disabled Ethernet on 1st boot + ln -sf /boot/bin/orangepipc.bin /boot/script.bin + NEWHOSTNAME="orangepipc" + fi + ;; esac - NEWHOSTNAME="$(echo "${MACHINE}" | tr '[:upper:]' '[:lower:]' | sed -e 's/+/plus/' -e 's/\ //g')" echo "${NEWHOSTNAME}" >/etc/hostname sed -i "s/orangepih3/${NEWHOSTNAME}/" /etc/hosts rm /boot/bin/orangepih3.bin From 8644413afdf69ca0356f5808ba5a4fe5eb7ec083 Mon Sep 17 00:00:00 2001 From: Thomas Kaiser Date: Tue, 1 Mar 2016 06:38:10 +0100 Subject: [PATCH 14/15] Update H3 Mini FAQ --- documentation/H3_mini_faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/H3_mini_faq.md b/documentation/H3_mini_faq.md index 028834340a..5294b77c66 100644 --- a/documentation/H3_mini_faq.md +++ b/documentation/H3_mini_faq.md @@ -21,7 +21,7 @@ Armbian supports starting with release 5.04 all available H3 based Orange Pi boa ***Known issues with 5.04*** -- It seems auto detection for the Orange Pi 2 doesn't work properly. Please have a look [in the forum](http://forum.armbian.com/index.php/topic/617-wip-orange-pi-one-support-for-the-upcoming-orange-pi-one/?p=5718). Will be fixed in 5.05 if we ever get feedback (otherwise image for Orange Pi 2 will be withdrawn +- Auto detection for the Orange Pi 2 doesn't work properly. Please have a look [for a manual fix](http://forum.armbian.com/index.php/topic/617-wip-orange-pi-one-support-for-the-upcoming-orange-pi-one/?p=5718) or wait for 5.05 where this will be fixed - Mali acceleration currently only working for root user. Please apply [a fix](http://forum.armbian.com/index.php/topic/617-wip-orange-pi-one-support-for-the-upcoming-orange-pi-one/?p=5719) manually or wait for 5.05 to fix this ***Important to know*** From e5c108812409644bfcfbb668cf13e9a7576cdb68 Mon Sep 17 00:00:00 2001 From: Igor Pecovnik Date: Tue, 1 Mar 2016 22:27:09 +0100 Subject: [PATCH 15/15] Banana M1 / M1+ / Pro micro fixes in legacy and vanilla kernel. --- config/bananapipro.fex | 4 +- config/linux-sunxi-next.config | 22 +++-- configuration.sh | 4 +- documentation/logbook.md | 9 ++ makeboarddeb.sh | 3 + .../bananapipro-wifi-codec-led-fix.patch | 94 +++++++++++++++++++ .../u-boot-default/bananapi-enable-ldo4.patch | 19 ++++ .../u-boot-next/bananapi-enable-ldo4.patch | 9 ++ scripts/sunxi-musb | 39 ++++++++ upgrade.sh | 4 +- 10 files changed, 191 insertions(+), 16 deletions(-) create mode 100644 patch/kernel/sunxi-next/bananapipro-wifi-codec-led-fix.patch create mode 100644 patch/u-boot/u-boot-default/bananapi-enable-ldo4.patch create mode 100644 scripts/sunxi-musb diff --git a/config/bananapipro.fex b/config/bananapipro.fex index 275521be59..a5c1b74100 100644 --- a/config/bananapipro.fex +++ b/config/bananapipro.fex @@ -819,7 +819,7 @@ kp_out7 = port:PH27<4><1> [usbc0] usb_used = 1 usb_port_type = 2 -usb_detect_type = 1 +usb_detect_type = 0 usb_id_gpio = port:PH04<0><1> usb_det_vbus_gpio = "axp_ctrl" usb_drv_vbus_gpio = port:PB09<1><0><0> @@ -969,7 +969,7 @@ switch_used = 0 [leds_para] leds_used = 1 -leds_num = 2 +leds_num = 1 leds_pin_1 = port:PH24<1><0> leds_name_1 = "green:ph24:led1" leds_trigger_1 = "mmc0" diff --git a/config/linux-sunxi-next.config b/config/linux-sunxi-next.config index ea3f59f1e5..ba43151f9a 100644 --- a/config/linux-sunxi-next.config +++ b/config/linux-sunxi-next.config @@ -3949,7 +3949,7 @@ CONFIG_USBIP_CORE=m CONFIG_USBIP_VHCI_HCD=m CONFIG_USBIP_HOST=m # CONFIG_USBIP_DEBUG is not set -CONFIG_USB_MUSB_HDRC=m +CONFIG_USB_MUSB_HDRC=y # CONFIG_USB_MUSB_HOST is not set # CONFIG_USB_MUSB_GADGET is not set CONFIG_USB_MUSB_DUAL_ROLE=y @@ -3957,7 +3957,7 @@ CONFIG_USB_MUSB_DUAL_ROLE=y # # Platform Glue Layer # -CONFIG_USB_MUSB_SUNXI=m +CONFIG_USB_MUSB_SUNXI=y # # MUSB DMA mode @@ -3968,9 +3968,10 @@ CONFIG_USB_MUSB_SUNXI=m # CONFIG_USB_CHIPIDEA is not set CONFIG_USB_ISP1760=m CONFIG_USB_ISP1760_HCD=y -CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_ISP1761_UDC=y +# CONFIG_USB_ISP1760_HOST_ROLE is not set # CONFIG_USB_ISP1760_GADGET_ROLE is not set -# CONFIG_USB_ISP1760_DUAL_ROLE is not set +CONFIG_USB_ISP1760_DUAL_ROLE=y # # USB port drivers @@ -4082,7 +4083,7 @@ CONFIG_NOP_USB_XCEIV=y # CONFIG_USB_GPIO_VBUS is not set # CONFIG_USB_ISP1301 is not set # CONFIG_USB_ULPI is not set -CONFIG_USB_GADGET=m +CONFIG_USB_GADGET=y # CONFIG_USB_GADGET_DEBUG is not set # CONFIG_USB_GADGET_DEBUG_FILES is not set # CONFIG_USB_GADGET_DEBUG_FS is not set @@ -4115,23 +4116,24 @@ CONFIG_USB_F_EEM=m CONFIG_USB_F_SUBSET=m CONFIG_USB_F_RNDIS=m CONFIG_USB_F_MASS_STORAGE=m -CONFIG_USB_F_UAC2=m +CONFIG_USB_F_UAC1=m CONFIG_USB_F_UVC=m CONFIG_USB_F_HID=m +CONFIG_USB_F_PRINTER=m # CONFIG_USB_CONFIGFS is not set # CONFIG_USB_ZERO is not set CONFIG_USB_AUDIO=m -# CONFIG_GADGET_UAC1 is not set +CONFIG_GADGET_UAC1=y CONFIG_USB_ETH=m CONFIG_USB_ETH_RNDIS=y CONFIG_USB_ETH_EEM=y # CONFIG_USB_G_NCM is not set -# CONFIG_USB_GADGETFS is not set +CONFIG_USB_GADGETFS=m # CONFIG_USB_FUNCTIONFS is not set CONFIG_USB_MASS_STORAGE=m CONFIG_USB_G_SERIAL=m # CONFIG_USB_MIDI_GADGET is not set -# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_PRINTER=m CONFIG_USB_CDC_COMPOSITE=m CONFIG_USB_G_ACM_MS=m CONFIG_USB_G_MULTI=m @@ -4140,7 +4142,7 @@ CONFIG_USB_G_MULTI_RNDIS=y CONFIG_USB_G_HID=m # CONFIG_USB_G_DBGP is not set CONFIG_USB_G_WEBCAM=m -CONFIG_USB_LED_TRIG=y +# CONFIG_USB_LED_TRIG is not set # CONFIG_UWB is not set CONFIG_MMC=y # CONFIG_MMC_DEBUG is not set diff --git a/configuration.sh b/configuration.sh index dc9531427c..8feb628c24 100644 --- a/configuration.sh +++ b/configuration.sh @@ -174,11 +174,11 @@ case $BOARD in DESKTOP_TARGET="trusty,next" ;; - bananapi)#enabled + bananapipro)#enabled #description A20 dual core 1Gb SoC #build 6 LINUXFAMILY="sun7i" - BOOTCONFIG="Bananapi_defconfig" + BOOTCONFIG="Bananapro_defconfig" MODULES="hci_uart gpio_sunxi rfcomm hidp sunxi-ir bonding spi_sun7i 8021q a20_tp #ap6211" MODULES_NEXT="brcmfmac bonding" DESKTOP_TARGET="trusty,%" diff --git a/documentation/logbook.md b/documentation/logbook.md index 05c8dd1ec1..48ef4518ca 100644 --- a/documentation/logbook.md +++ b/documentation/logbook.md @@ -1,5 +1,14 @@ # Release history +**v5.04 / 1.3.2016** + +- Banana M1/PRO/M1+ rebuilded +- fixed SATA problem +- set OTG port in HOST mode in vanilla kernel +- wireless is working on PRO out of the box +- added utility to switch between OTG and HOST in vanilla kernel +- Bugs left: OTG mode not working, M1+ wireless not work in vanilla kernel + **v5.04 / 28.2.2016** - H3 images rebuilded diff --git a/makeboarddeb.sh b/makeboarddeb.sh index 0b1bfa9d67..ec5cd2043b 100644 --- a/makeboarddeb.sh +++ b/makeboarddeb.sh @@ -71,6 +71,9 @@ create_board_package (){ mkdir -p $destination/usr/local/bin tar xfz $SRC/lib/bin/temper.tgz -C $destination/usr/local/bin + # add USB OTG port mode switcher + install -m 755 $SRC/lib/scripts/sunxi-musb $destination/usr/local/bin + # replace hostapd from latest self compiled & patched mkdir -p $destination/usr/sbin/ tar xfz $SRC/lib/bin/hostapd25-rt.tgz -C $destination/usr/sbin/ diff --git a/patch/kernel/sunxi-next/bananapipro-wifi-codec-led-fix.patch b/patch/kernel/sunxi-next/bananapipro-wifi-codec-led-fix.patch new file mode 100644 index 0000000000..dee723a1a3 --- /dev/null +++ b/patch/kernel/sunxi-next/bananapipro-wifi-codec-led-fix.patch @@ -0,0 +1,94 @@ +diff --git a/arch/arm/boot/dts/sun7i-a20-bananapro.dts b/arch/arm/boot/dts/sun7i-a20-bananapro.dts +index 18fcc87..d5519c6 100644 +--- a/arch/arm/boot/dts/sun7i-a20-bananapro.dts ++++ b/arch/arm/boot/dts/sun7i-a20-bananapro.dts +@@ -66,13 +66,14 @@ + pinctrl-0 = <&led_pins_bananapro>; + + blue { +- label = "bananapro:blue:usr"; ++ label = "bananapro:blue:usr"; + gpios = <&pio 6 2 GPIO_ACTIVE_HIGH>; + }; + + green { + label = "bananapro:green:usr"; + gpios = <&pio 7 24 GPIO_ACTIVE_HIGH>; ++ linux,default-trigger = "mmc0"; + }; + }; + +@@ -95,6 +96,8 @@ + regulator-name = "vmmc3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ regulator-boot-on; + enable-active-high; + gpio = <&pio 7 22 GPIO_ACTIVE_HIGH>; + }; +@@ -104,6 +107,10 @@ + status = "okay"; + }; + ++&codec { ++ status = "okay"; ++}; ++ + &ehci0 { + status = "okay"; + }; +@@ -164,12 +171,26 @@ + }; + + &mmc3 { ++ #address-cells = <1>; ++ #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&mmc3_pins_a>; + vmmc-supply = <®_vmmc3>; + bus-width = <4>; + non-removable; ++ enable-sdio-wakeup; + status = "okay"; ++ ++/* ++ brcmf: bcrmf@1 { ++ reg = <1>; ++ compatible = "brcm,bcm4329-fmac"; ++ interrupt-parent = <&pio>; ++ interrupts = <15 8>; ++ interrupt-names = "host-wake"; ++ }; ++*/ ++ + }; + + &ohci0 { +@@ -180,6 +201,10 @@ + status = "okay"; + }; + ++&otg_sram { ++ status = "okay"; ++}; ++ + &pio { + gmac_power_pin_bananapro: gmac_power_pin@0 { + allwinner,pins = "PH23"; +@@ -262,8 +287,11 @@ + status = "okay"; + }; + +-&usbphy { +- usb1_vbus-supply = <®_usb1_vbus>; +- usb2_vbus-supply = <®_usb2_vbus>; ++&usb_otg { ++ dr_mode = "host"; + status = "okay"; + }; ++ ++&usbphy { ++ status = "okay"; ++}; +\ No newline at end of file diff --git a/patch/u-boot/u-boot-default/bananapi-enable-ldo4.patch b/patch/u-boot/u-boot-default/bananapi-enable-ldo4.patch new file mode 100644 index 0000000000..47a454b79c --- /dev/null +++ b/patch/u-boot/u-boot-default/bananapi-enable-ldo4.patch @@ -0,0 +1,19 @@ +diff --git a/configs/Bananapi_defconfig b/configs/Bananapi_defconfig +index 6cbb76c..5ed845c 100644 +--- a/configs/Bananapi_defconfig ++++ b/configs/Bananapi_defconfig +@@ -15,3 +15,4 @@ CONFIG_CMD_GPIO=y + CONFIG_NETCONSOLE=y + CONFIG_ETH_DESIGNWARE=y + CONFIG_USB_EHCI_HCD=y ++CONFIG_AXP_ALDO4_VOLT=2500 +diff --git a/configs/Bananapro_defconfig b/configs/Bananapro_defconfig +index 40588b9..f1554bc 100644 +--- a/configs/Bananapro_defconfig ++++ b/configs/Bananapro_defconfig +@@ -17,3 +17,4 @@ CONFIG_CMD_GPIO=y + CONFIG_NETCONSOLE=y + CONFIG_ETH_DESIGNWARE=y + CONFIG_USB_EHCI_HCD=y ++CONFIG_AXP_ALDO4_VOLT=2500 +\ No newline at end of file diff --git a/patch/u-boot/u-boot-next/bananapi-enable-ldo4.patch b/patch/u-boot/u-boot-next/bananapi-enable-ldo4.patch index 161bde831e..47a454b79c 100644 --- a/patch/u-boot/u-boot-next/bananapi-enable-ldo4.patch +++ b/patch/u-boot/u-boot-next/bananapi-enable-ldo4.patch @@ -7,4 +7,13 @@ index 6cbb76c..5ed845c 100644 CONFIG_ETH_DESIGNWARE=y CONFIG_USB_EHCI_HCD=y +CONFIG_AXP_ALDO4_VOLT=2500 +diff --git a/configs/Bananapro_defconfig b/configs/Bananapro_defconfig +index 40588b9..f1554bc 100644 +--- a/configs/Bananapro_defconfig ++++ b/configs/Bananapro_defconfig +@@ -17,3 +17,4 @@ CONFIG_CMD_GPIO=y + CONFIG_NETCONSOLE=y + CONFIG_ETH_DESIGNWARE=y + CONFIG_USB_EHCI_HCD=y ++CONFIG_AXP_ALDO4_VOLT=2500 \ No newline at end of file diff --git a/scripts/sunxi-musb b/scripts/sunxi-musb new file mode 100644 index 0000000000..d5a2e813a2 --- /dev/null +++ b/scripts/sunxi-musb @@ -0,0 +1,39 @@ +#!/bin/bash +# +# +# sunxi_musb +# +# Patches Device Tree Blob to modify dr_mode - function of the OTG port +# +# Usage: filename.dtb otg | host +# +# It searches for dtb files in /boot/dtb +# +# It's a part of Armbian project. + +if [[ -z $1 ]]; then + echo -e "OTG / HOST changer for DTB v1.0" + echo -e "\n`basename "$0"` filename.dtb otg | host" + echo -e "" + echo -e "\e[0;32mUsage example:\x1B[0m `basename "$0"` sun4i-a10-mini-xplus.dtb otg" + echo -e + exit +fi +[[ ! -f "/boot/dtb/$1" ]] && echo -e "[\e[0;31m Device tree blob /boot/dtb/$1 not found \x1B[0m]" + +if [[ $2 != "otg" && $2 != "host" ]]; then +echo -e "[\e[0;31m error \x1B[0m] Unkown parameter $2" +exit 2 +fi + +( dtc -I dtb -O dts /boot/dtb/$1 | grep dr_mode ) > /dev/null 2>&1 + +if [ $? -ne 0 ]; then +echo -e "[\e[0;31m error \x1B[0m] dr_mode undefined in /boot/dtb/$1" +exit 1 +fi + + +dtc -I dtb -O dts /boot/dtb/$1 | sed -e "s/dr_mode =.*/dr_mode = \"$2\";/" | dtc -I dts -O dtb -o /boot/dtb/$1 + +echo -e "[\e[0;32m o.k. \x1B[0m] $2 mode enabled in /boot/dtb/$1" diff --git a/upgrade.sh b/upgrade.sh index 0fca37de9d..a5fa21d909 100644 --- a/upgrade.sh +++ b/upgrade.sh @@ -182,7 +182,7 @@ select_boards () if [ -z "$BOARD" ]; then IFS=" " Options="Cubieboard A10 Cubieboard2 A20 Cubietruck A20 Lime-A10 A10 Lime \ -A20 Lime2 A20 Micro A20 Bananapi A20 Lamobo-R1 A20 Orangepi A20 Pcduino3nano A20" +A20 Lime2 A20 Micro A20 Bananapipro A20 Lamobo-R1 A20 Orangepi A20 Pcduino3nano A20" BoardOptions=($Options); BoardCmd=(dialog --title "Choose a board:" --backtitle "$backtitle" --menu "\n$infos" 20 60 26) BoardChoices=$("${BoardCmd[@]}" "${BoardOptions[@]}" 2>&1 >/dev/tty) @@ -216,7 +216,7 @@ if [[ $BRANCH == "vanilla" ]] ; then fi case $BOARD in -bananapi | bananapipro | lamobo-r1 | orangepi | orangepimini) +bananapipro | lamobo-r1 | orangepi | orangepimini) LINUXFAMILY="sun7i" if [[ $BRANCH == "vanilla" ]] ; then LINUXFAMILY="sunxi"; fi ;;