From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 14914 invoked from network); 22 Oct 2023 18:47:11 -0000 Received: from 9front.inri.net (168.235.81.73) by inbox.vuxu.org with ESMTPUTF8; 22 Oct 2023 18:47:11 -0000 Received: from gaff.inri.net ([168.235.71.243]) by 9front; Sun Oct 22 14:45:08 -0400 2023 Received: from [127.0.0.1] ([168.235.81.125]) by gaff; Sun Oct 22 14:45:08 -0400 2023 Date: Sun, 22 Oct 2023 14:45:07 -0400 From: Stanley Lieber To: 9front@9front.org In-Reply-To: <4C53B52B-3A22-46DF-8CE1-80BD3543F6EF@stanleylieber.com> References: <1734B8F2A873B2D850DB1C299ECACF8F@9front.org> <4C53B52B-3A22-46DF-8CE1-80BD3543F6EF@stanleylieber.com> Message-ID: MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable List-ID: <9front.9front.org> List-Help: X-Glyph: ➈ X-Bullshit: converged object-oriented app configuration event Subject: [9front] =?US-ASCII?Q?Re=3A_Fwd=3A_=5B9front-commits=5D_bcm=3A_add_wifi?= =?US-ASCII?Q?_driver_=28keegan=40undefinedbehaviour=2Eorg=29?= Reply-To: 9front@9front.org Precedence: bulk On October 22, 2023 2:43:42 PM EDT, Stanley Lieber = wrote: >this is for rpi, yes? is there a list of specific hardware this is known = to work with? > >sl > > >-------- Original Message -------- >From: commits@git=2E9front=2Eorg >Sent: October 22, 2023 10:53:02 AM EDT >To: 9front-commits@9front=2Eorg >Subject: [9front-commits] bcm: add wifi driver (keegan@undefinedbehaviour= =2Eorg) > > >Thanks Richard Miller >--- >diff f2cfee358f329519e913a20142d96b1e0029633c fb96a050f8a9d5f23da3557ba89= 251ffb73889bf >--- a/sys/src/9/bcm/emmc=2Ec Sun Oct 22 09:21:23 2023 >+++ b/sys/src/9/bcm/emmc=2Ec Sun Oct 22 10:53:02 2023 >@@ -129,6 +129,7 @@ >=20 > typedef struct Ctlr Ctlr; > struct Ctlr { >+ Rendez cardr; > Rendez r; > int fastclock; > ulong extclk; >@@ -266,6 +267,23 @@ > intrenable(IRQmmc, emmcinterrupt, nil, BUSUNKNOWN, io->name); > } >=20 >+int >+sdiocardintr(int wait) >+{ >+ u32int *r =3D (u32int*)EMMCREGS; >+ int i; >+ >+ WR(Interrupt, Cardintr); >+ while(((i =3D r[Interrupt]) & Cardintr) =3D=3D 0){ >+ if(!wait) >+ return 0; >+ WR(Irpten, r[Irpten] | Cardintr); >+ sleep(&emmc=2Ecardr, cardintready, 0); >+ } >+ WR(Interrupt, Cardintr); >+ return i; >+} >+ > static int > emmccmd(SDio*, SDiocmd *cmd, u32int arg, u32int *resp) > { >@@ -434,21 +452,25 @@ > i =3D r[Interrupt]; > if(i&(Datadone|Err)) > wakeup(&emmc=2Er); >+ if(i&Cardintr) >+ wakeup(&emmc=2Ecardr); > WR(Irpten, r[Irpten] & ~i); > } >=20 >+ >+SDio sdio =3D { >+ "emmc", >+ emmcinit, >+ emmcenable, >+ emmcinquiry, >+ emmccmd, >+ emmciosetup, >+ emmcio, >+ emmcbus, >+}; >+ > void > emmclink(void) > { >- static SDio io =3D { >- "emmc", >- emmcinit, >- emmcenable, >- emmcinquiry, >- emmccmd, >- emmciosetup, >- emmcio, >- emmcbus, >- }; >- addmmcio(&io); >+ addmmcio(&sdio); > } >--- /dev/null Sun Aug 27 23:09:05 2023 >+++ b/sys/src/9/bcm/ether4330=2Ec Sun Oct 22 10:53:02 2023 >@@ -0,0 +1,2411 @@ >+/* >+ * Broadcom bcm4330 wifi (sdio interface) >+ */ >+ >+#include "u=2Eh" >+#include "=2E=2E/port/lib=2Eh" >+#include "mem=2Eh" >+#include "dat=2Eh" >+#include "fns=2Eh" >+#include "io=2Eh" >+#include "=2E=2E/port/error=2Eh" >+#include "=2E=2E/port/netif=2Eh" >+#include "=2E=2E/port/sd=2Eh" >+#include "=2E=2E/port/etherif=2Eh" >+ >+#define CACHELINESZ 64 /* temp */ >+ >+extern SDio sdio; >+extern int sdiocardintr(int); >+ >+SDiocmd IO_SEND_OP_COND =3D { 5, 3, 0, 0, "IO_SEND_OP_COND" }; >+SDiocmd IO_RW_DIRECT =3D { 52, 1, 0, 0, "IO_RW_DIRECT" }; >+ >+enum{ >+ SDIODEBUG =3D 0, >+ SBDEBUG =3D 0, >+ EVENTDEBUG =3D 0, >+ VARDEBUG =3D 0, >+ FWDEBUG =3D 0, >+ >+ Corescansz =3D 512, >+ Uploadsz =3D 2048, >+ Sdpcmsz =3D 12, /* sizeof(Sdpcmsz) */ >+ Cmdsz =3D 16, /* sizeof(Cmd) */ >+ >+ SDfreq =3D 25*Mhz, /* standard SD frequency */ >+ SDfreqhs =3D 50*Mhz, /* high speed frequency */ >+ >+ Wifichan =3D 0, /* default channel */ >+ Firmwarecmp =3D 1, >+ >+ ARMcm3 =3D 0x82A, >+ ARM7tdmi =3D 0x825, >+ ARMcr4 =3D 0x83E, >+ >+ Fn0 =3D 0, >+ Fn1 =3D 1, >+ Fn2 =3D 2, >+ Fbr1 =3D 0x100, >+ Fbr2 =3D 0x200, >+ >+ /* CCCR */ >+ Ioenable =3D 0x02, >+ Ioready =3D 0x03, >+ Intenable =3D 0x04, >+ Intpend =3D 0x05, >+ Ioabort =3D 0x06, >+ Busifc =3D 0x07, >+ Capability =3D 0x08, >+ Blksize =3D 0x10, >+ Highspeed =3D 0x13, >+ >+ /* SELECT_CARD args */ >+ Rcashift =3D 16, >+ >+ /* SEND_OP_COND args */ >+ Hcs =3D 1<<30, /* host supports SDHC & SDXC */ >+ V3_3 =3D 3<<20, /* 3=2E2-3=2E4 volts */ >+ V2_8 =3D 3<<15, /* 2=2E7-2=2E9 volts */ >+ V2_0 =3D 1<<8, /* 2=2E0-2=2E1 volts */ >+ S18R =3D 1<<24, /* switch to 1=2E8V request */ >+ >+ /* Sonics Silicon Backplane (access to cores on chip) */ >+ Sbwsize =3D 0x8000, >+ Sb32bit =3D 0x8000, >+ Sbaddr =3D 0x1000a, >+ Enumbase =3D 0x18000000, >+ Framectl=3D 0x1000d, >+ Rfhalt =3D 0x01, >+ Wfhalt =3D 0x02, >+ Clkcsr =3D 0x1000e, >+ ForceALP =3D 0x01, /* active low-power clock */ >+ ForceHT =3D 0x02, /* high throughput clock */ >+ ForceILP =3D 0x04, /* idle low-power clock */ >+ ReqALP =3D 0x08, >+ ReqHT =3D 0x10, >+ Nohwreq =3D 0x20, >+ ALPavail =3D 0x40, >+ HTavail =3D 0x80, >+ Pullups =3D 0x1000f, >+ Wfrmcnt =3D 0x10019, >+ Rfrmcnt =3D 0x1001b, >+ =09 >+ /* core control regs */ >+ Ioctrl =3D 0x408, >+ Resetctrl =3D 0x800, >+ >+ /* socram regs */ >+ Coreinfo =3D 0x00, >+ Bankidx =3D 0x10, >+ Bankinfo =3D 0x40, >+ Bankpda =3D 0x44, >+ >+ /* armcr4 regs */ >+ Cr4Cap =3D 0x04, >+ Cr4Bankidx =3D 0x40, >+ Cr4Bankinfo =3D 0x44, >+ Cr4Cpuhalt =3D 0x20, >+ >+ /* chipcommon regs */ >+ Gpiopullup =3D 0x58, >+ Gpiopulldown =3D 0x5c, >+ Chipctladdr =3D 0x650, >+ Chipctldata =3D 0x654, >+ >+ /* sdio core regs */ >+ Intstatus =3D 0x20, >+ Fcstate =3D 1<<4, >+ Fcchange =3D 1<<5, >+ FrameInt =3D 1<<6, >+ MailboxInt =3D 1<<7, >+ Intmask =3D 0x24, >+ Sbmbox =3D 0x40, >+ Sbmboxdata =3D 0x48, >+ Hostmboxdata=3D 0x4c, >+ Fwready =3D 0x80, >+ >+ /* wifi control commands */ >+ GetVar =3D 262, >+ SetVar =3D 263, >+ >+ /* status */ >+ Disconnected=3D 0, >+ Connecting, >+ Connected, >+}; >+ >+typedef struct Ctlr Ctlr; >+ >+enum{ >+ Wpa =3D 1, >+ Wep =3D 2, >+ Wpa2 =3D 3, >+ WNameLen =3D 32, >+ WNKeys =3D 4, >+ WKeyLen =3D 32, >+ WMinKeyLen =3D 5, >+ WMaxKeyLen =3D 13, >+}; >+ >+typedef struct WKey WKey; >+struct WKey >+{ >+ ushort len; >+ char dat[WKeyLen]; >+}; >+ >+struct Ctlr { >+ Ether* edev; >+ QLock cmdlock; >+ QLock pktlock; >+ QLock tlock; >+ QLock alock; >+ Lock txwinlock; >+ Rendez cmdr; >+ Rendez joinr; >+ int joinstatus; >+ int cryptotype; >+ int chanid; >+ char essid[WNameLen + 1]; >+ WKey keys[WNKeys]; >+ Block *rsp; >+ Block *scanb; >+ int scansecs; >+ int status; >+ int chipid; >+ int chiprev; >+ int armcore; >+ char *regufile; >+ union { >+ u32int i; >+ uchar c[4]; >+ } resetvec; >+ ulong chipcommon; >+ ulong armctl; >+ ulong armregs; >+ ulong d11ctl; >+ ulong socramregs; >+ ulong socramctl; >+ ulong sdregs; >+ int sdiorev; >+ int socramrev; >+ ulong socramsize; >+ ulong rambase; >+ short reqid; >+ uchar fcmask; >+ uchar txwindow; >+ uchar txseq; >+ uchar rxseq; >+}; >+ >+enum{ >+ CMauth, >+ CMchannel, >+ CMcrypt, >+ CMessid, >+ CMkey1, >+ CMkey2, >+ CMkey3, >+ CMkey4, >+ CMrxkey, >+ CMrxkey0, >+ CMrxkey1, >+ CMrxkey2, >+ CMrxkey3, >+ CMtxkey, >+ CMdebug, >+ CMjoin, >+}; >+ >+static Cmdtab cmds[] =3D { >+ {CMauth, "auth", 2}, >+ {CMchannel, "channel", 2}, >+ {CMcrypt, "crypt", 2}, >+ {CMessid, "essid", 2}, >+ {CMkey1, "key1", 2}, >+ {CMkey2, "key1", 2}, >+ {CMkey3, "key1", 2}, >+ {CMkey4, "key1", 2}, >+ {CMrxkey, "rxkey", 3}, >+ {CMrxkey0, "rxkey0", 3}, >+ {CMrxkey1, "rxkey1", 3}, >+ {CMrxkey2, "rxkey2", 3}, >+ {CMrxkey3, "rxkey3", 3}, >+ {CMtxkey, "txkey", 3}, >+ {CMdebug, "debug", 2}, >+ {CMjoin, "join", 5}, >+}; >+ >+typedef struct Sdpcm Sdpcm; >+typedef struct Cmd Cmd; >+struct Sdpcm { >+ uchar len[2]; >+ uchar lenck[2]; >+ uchar seq; >+ uchar chanflg; >+ uchar nextlen; >+ uchar doffset; >+ uchar fcmask; >+ uchar window; >+ uchar version; >+ uchar pad; >+}; >+ >+struct Cmd { >+ uchar cmd[4]; >+ uchar len[4]; >+ uchar flags[2]; >+ uchar id[2]; >+ uchar status[4]; >+}; >+ >+static char config40181[] =3D "bcmdhd=2Ecal=2E40181"; >+static char config40183[] =3D "bcmdhd=2Ecal=2E40183=2E26MHz"; >+ >+struct { >+ int chipid; >+ int chiprev; >+ char *fwfile; >+ char *cfgfile; >+ char *regufile; >+} firmware[] =3D { >+ { 0x4330, 3, "fw_bcm40183b1=2Ebin", config40183, 0 }, >+ { 0x4330, 4, "fw_bcm40183b2=2Ebin", config40183, 0 }, >+ { 43362, 0, "fw_bcm40181a0=2Ebin", config40181, 0 }, >+ { 43362, 1, "fw_bcm40181a2=2Ebin", config40181, 0 }, >+ { 43430, 1, "brcmfmac43430-sdio=2Ebin", "brcmfmac43430-sdio=2Etxt", 0 }= , >+ { 43430, 2, "brcmfmac43436-sdio=2Ebin", "brcmfmac43436-sdio=2Etxt", "b= rcmfmac43436-sdio=2Eclm_blob" }, >+ { 0x4345, 6, "brcmfmac43455-sdio=2Ebin", "brcmfmac43455-sdio=2Etxt", "b= rcmfmac43455-sdio=2Eclm_blob" }, >+ { 0x4345, 9, "brcmfmac43456-sdio=2Ebin", "brcmfmac43456-sdio=2Etxt", "b= rcmfmac43456-sdio=2Eclm_blob" }, >+}; >+ >+static QLock sdiolock; >+static int iodebug; >+ >+static void etherbcmintr(void *); >+static void bcmevent(Ctlr*, uchar*, int); >+static void wlscanresult(Ether*, uchar*, int); >+static void wlsetvar(Ctlr*, char*, void*, int); >+ >+static uchar* >+put2(uchar *p, short v) >+{ >+ p[0] =3D v; >+ p[1] =3D v >> 8; >+ return p + 2; >+} >+ >+static uchar* >+put4(uchar *p, long v) >+{ >+ p[0] =3D v; >+ p[1] =3D v >> 8; >+ p[2] =3D v >> 16; >+ p[3] =3D v >> 24; >+ return p + 4; >+} >+ >+static ushort >+get2(uchar *p) >+{ >+ return p[0] | p[1]<<8; >+} >+ >+static ulong >+get4(uchar *p) >+{ >+ return p[0] | p[1]<<8 | p[2]<<16 | p[3]<<24; >+} >+ >+static void >+dump(char *s, void *a, int n) >+{ >+ int i; >+ uchar *p; >+ >+ p =3D a; >+ print("%s:", s); >+ for(i =3D 0; i < n; i++) >+ print("%c%2=2E2x", i&15? ' ' : '\n', *p++); >+ print("\n"); >+} >+ >+/* >+ * SDIO communication with dongle >+ */ >+static ulong >+sdiocmd_locked(SDiocmd *cmd, ulong arg) >+{ >+ u32int resp[4]; >+ >+ sdio=2Ecmd(&sdio, cmd, arg, resp); >+ return resp[0]; >+} >+ >+static ulong >+sdiocmd(SDiocmd *cmd, ulong arg) >+{ >+ ulong r; >+ >+ qlock(&sdiolock); >+ if(waserror()){ >+ if(SDIODEBUG) print("sdiocmd error: cmd %s arg %lux\n", cmd->name, arg= ); >+ qunlock(&sdiolock); >+ nexterror(); >+ } >+ r =3D sdiocmd_locked(cmd, arg); >+ qunlock(&sdiolock); >+ poperror(); >+ return r; >+ >+} >+ >+static ulong >+trysdiocmd(SDiocmd *cmd, ulong arg) >+{ >+ ulong r; >+ >+ if(waserror()) >+ return 0; >+ r =3D sdiocmd(cmd, arg); >+ poperror(); >+ return r; >+} >+ >+static int >+sdiord(int fn, int addr) >+{ >+ int r; >+ >+ r =3D sdiocmd(&IO_RW_DIRECT, (0<<31)|((fn&7)<<28)|((addr&0x1FFFF)<<9)); >+ if(r & 0xCF00){ >+ print("ether4330: sdiord(%x, %x) fail: %2=2E2ux %2=2E2ux\n", fn, addr,= (r>>8)&0xFF, r&0xFF); >+ error(Eio); >+ } >+ return r & 0xFF; >+} >+ >+static void >+sdiowr(int fn, int addr, int data) >+{ >+ int r; >+ int retry; >+ ulong arg; >+ >+ r =3D 0; >+ for(retry =3D 0; retry < 10; retry++){ >+ arg =3D (1<<31)|((fn&7)<<28)|((addr&0x1FFFF)<<9)|(data&0xFF); >+ if((arg & ~0xFF) =3D=3D (1<<31|0<<28|7<<9)){ >+ switch(arg&3){ >+ case 0: >+ sdio=2Ebus(&sdio, 1, 0); >+ break; >+ case 2: >+ sdio=2Ebus(&sdio, 4, 0); >+ break; >+ } >+ } >+ r =3D sdiocmd(&IO_RW_DIRECT, arg); >+ if((r & 0xCF00) =3D=3D 0) >+ return; >+ } >+ print("ether4330: sdiowr(%x, %x, %x) fail: %2=2E2ux %2=2E2ux\n", fn, ad= dr, data, (r>>8)&0xFF, r&0xFF); >+ error(Eio); >+} >+ >+static void >+sdiorwext(int fn, int write, void *a, int len, int addr, int incr) >+{ >+ int bsize, blk, bcount, m; >+ SDiocmd cmd =3D { 53, 1, 0, 0, "IO_RW_EXTENDED" }; >+ >+ bsize =3D fn =3D=3D Fn2? 512 : 64; >+ while(len > 0){ >+ if(len >=3D 511*bsize){ >+ blk =3D 1; >+ bcount =3D 511; >+ m =3D bcount*bsize; >+ }else if(len > bsize){ >+ blk =3D 1; >+ bcount =3D len/bsize; >+ m =3D bcount*bsize; >+ }else{ >+ blk =3D 0; >+ bcount =3D len; >+ m =3D bcount; >+ } >+ qlock(&sdiolock); >+ if(waserror()){ >+ print("ether4330: sdiorwext fail: %s\n", up->errstr); >+ qunlock(&sdiolock); >+ nexterror(); >+ } >+ cmd=2Edata =3D write? 2 : 1; /* Host2card : Card2host */ >+ if(blk){ >+ cmd=2Edata +=3D 2; /* Multiblock | Blkcnten */ >+ sdio=2Eiosetup(&sdio, write, a, bsize, bcount); >+ }else >+ sdio=2Eiosetup(&sdio, write, a, bcount, 1); >+ sdiocmd_locked(&cmd, write<<31 | (fn&7)<<28 | blk<<27 | incr<<26 | (ad= dr&0x1FFFF)<<9 | (bcount&0x1FF)); >+ sdio=2Eio(&sdio, write, a, m); >+ qunlock(&sdiolock); >+ poperror(); >+ len -=3D m; >+ a =3D (char*)a + m; >+ if(incr) >+ addr +=3D m; >+ } >+} >+ >+static void >+sdioset(int fn, int addr, int bits) >+{ >+ sdiowr(fn, addr, sdiord(fn, addr) | bits); >+} >+=09 >+static void >+sdioinit(void) >+{ >+ ulong ocr, rca; >+ int i; >+ >+ /* disconnect emmc from SD card (connect sdhost instead) */ >+ for(i =3D 48; i <=3D 53; i++) >+ gpiosel(i, Alt0); >+ /* connect emmc to wifi */ >+ for(i =3D 34; i <=3D 39; i++){ >+ gpiosel(i, Alt3); >+ if(i =3D=3D 34) >+ gpiopulloff(i); >+ else >+ gpiopullup(i); >+ } >+ sdio=2Einit(&sdio); >+ sdio=2Eenable(&sdio); >+ sdiocmd(&GO_IDLE_STATE, 0); >+ ocr =3D trysdiocmd(&IO_SEND_OP_COND, 0); >+ i =3D 0; >+ while((ocr & (1<<31)) =3D=3D 0){ >+ if(++i > 5){ >+ print("ether4330: no response to sdio access: ocr =3D %lux\n", ocr); >+ error(Eio); >+ } >+ ocr =3D trysdiocmd(&IO_SEND_OP_COND, V3_3); >+ tsleep(&up->sleep, return0, nil, 100); >+ } >+ rca =3D sdiocmd(&SEND_RELATIVE_ADDR, 0) >> Rcashift; >+ sdiocmd(&SELECT_CARD, rca << Rcashift); >+ sdio=2Ebus(&sdio, 0, SDfreq); >+ sdioset(Fn0, Highspeed, 2); >+ sdioset(Fn0, Busifc, 2); /* bus width 4 */ >+ sdiowr(Fn0, Fbr1+Blksize, 64); >+ sdiowr(Fn0, Fbr1+Blksize+1, 64>>8); >+ sdiowr(Fn0, Fbr2+Blksize, 512); >+ sdiowr(Fn0, Fbr2+Blksize+1, 512>>8); >+ sdioset(Fn0, Ioenable, 1<+ sdiowr(Fn0, Intenable, 0); >+ for(i =3D 0; !(sdiord(Fn0, Ioready) & 1<+ if(i =3D=3D 10){ >+ print("ether4330: can't enable SDIO function\n"); >+ error(Eio); >+ } >+ tsleep(&up->sleep, return0, nil, 100); >+ } >+} >+ >+static void >+sdioreset(void) >+{ >+ sdiowr(Fn0, Ioabort, 1<<3); /* reset */ >+} >+ >+static void >+sdioabort(int fn) >+{ >+ sdiowr(Fn0, Ioabort, fn); >+} >+ >+/* >+ * Chip register and memory access via SDIO >+ */ >+ >+static void >+cfgw(ulong off, int val) >+{ >+ sdiowr(Fn1, off, val); >+} >+ >+static int >+cfgr(ulong off) >+{ >+ return sdiord(Fn1, off); >+} >+ >+static ulong >+cfgreadl(int fn, ulong off) >+{ >+ uchar cbuf[2*CACHELINESZ]; >+ uchar *p; >+ >+ p =3D (uchar*)ROUND((uintptr)cbuf, CACHELINESZ); >+ memset(p, 0, 4); >+ sdiorwext(fn, 0, p, 4, off|Sb32bit, 1); >+ if(SDIODEBUG) print("cfgreadl %lux: %2=2E2x %2=2E2x %2=2E2x %2=2E2x\n",= off, p[0], p[1], p[2], p[3]); >+ return p[0] | p[1]<<8 | p[2]<<16 | p[3]<<24; >+} >+ >+static void >+cfgwritel(int fn, ulong off, u32int data) >+{ >+ uchar cbuf[2*CACHELINESZ]; >+ uchar *p; >+ int retry; >+ >+ p =3D (uchar*)ROUND((uintptr)cbuf, CACHELINESZ); >+ put4(p, data); >+ if(SDIODEBUG) print("cfgwritel %lux: %2=2E2x %2=2E2x %2=2E2x %2=2E2x\n"= , off, p[0], p[1], p[2], p[3]); >+ retry =3D 0; >+ while(waserror()){ >+ print("ether4330: cfgwritel retry %lux %ux\n", off, data); >+ sdioabort(fn); >+ if(++retry =3D=3D 3) >+ nexterror(); >+ } >+ sdiorwext(fn, 1, p, 4, off|Sb32bit, 1); >+ poperror(); >+} >+ >+static void >+sbwindow(ulong addr) >+{ >+ addr &=3D ~(Sbwsize-1); >+ cfgw(Sbaddr, addr>>8); >+ cfgw(Sbaddr+1, addr>>16); >+ cfgw(Sbaddr+2, addr>>24); >+} >+ >+static void >+sbrw(int fn, int write, uchar *buf, int len, ulong off) >+{ >+ int n; >+ USED(fn); >+ >+ if(waserror()){ >+ print("ether4330: sbrw err off %lux len %ud\n", off, len); >+ nexterror(); >+ } >+ if(write){ >+ if(len >=3D 4){ >+ n =3D len; >+ n &=3D ~3; >+ sdiorwext(Fn1, write, buf, n, off|Sb32bit, 1); >+ off +=3D n; >+ buf +=3D n; >+ len -=3D n; >+ } >+ while(len > 0){ >+ sdiowr(Fn1, off|Sb32bit, *buf); >+ off++; >+ buf++; >+ len--; >+ } >+ }else{ >+ if(len >=3D 4){ >+ n =3D len; >+ n &=3D ~3; >+ sdiorwext(Fn1, write, buf, n, off|Sb32bit, 1); >+ off +=3D n; >+ buf +=3D n; >+ len -=3D n; >+ } >+ while(len > 0){ >+ *buf =3D sdiord(Fn1, off|Sb32bit); >+ off++; >+ buf++; >+ len--; >+ } >+ } >+ poperror(); >+} >+ >+static void >+sbmem(int write, uchar *buf, int len, ulong off) >+{ >+ ulong n; >+ >+ n =3D ROUNDUP(off, Sbwsize) - off; >+ if(n =3D=3D 0) >+ n =3D Sbwsize; >+ while(len > 0){ >+ if(n > len) >+ n =3D len; >+ sbwindow(off); >+ sbrw(Fn1, write, buf, n, off & (Sbwsize-1)); >+ off +=3D n; >+ buf +=3D n; >+ len -=3D n; >+ n =3D Sbwsize; >+ } >+} >+ >+static void >+packetrw(int write, uchar *buf, int len) >+{ >+ int n; >+ int retry; >+ >+ n =3D 2048; >+ while(len > 0){ >+ if(n > len) >+ n =3D ROUND(len, 4); >+ retry =3D 0; >+ while(waserror()){ >+ sdioabort(Fn2); >+ if(++retry =3D=3D 3) >+ nexterror(); >+ } >+ sdiorwext(Fn2, write, buf, n, Enumbase, 0); >+ poperror(); >+ buf +=3D n; >+ len -=3D n; >+ } >+} >+ >+/* >+ * Configuration and control of chip cores via Silicon Backplane >+ */ >+ >+static void >+sbdisable(ulong regs, int pre, int ioctl) >+{ >+ sbwindow(regs); >+ if((cfgreadl(Fn1, regs + Resetctrl) & 1) !=3D 0){ >+ cfgwritel(Fn1, regs + Ioctrl, 3|ioctl); >+ cfgreadl(Fn1, regs + Ioctrl); >+ return; >+ } >+ cfgwritel(Fn1, regs + Ioctrl, 3|pre); >+ cfgreadl(Fn1, regs + Ioctrl); >+ cfgwritel(Fn1, regs + Resetctrl, 1); >+ microdelay(10); >+ while((cfgreadl(Fn1, regs + Resetctrl) & 1) =3D=3D 0) >+ ; >+ cfgwritel(Fn1, regs + Ioctrl, 3|ioctl); >+ cfgreadl(Fn1, regs + Ioctrl); >+} >+ >+static void >+sbreset(ulong regs, int pre, int ioctl) >+{ >+ sbdisable(regs, pre, ioctl); >+ sbwindow(regs); >+ if(SBDEBUG) print("sbreset %#lux %#lux %#lux ->", regs, >+ cfgreadl(Fn1, regs+Ioctrl), cfgreadl(Fn1, regs+Resetctrl)); >+ while((cfgreadl(Fn1, regs + Resetctrl) & 1) !=3D 0){ >+ cfgwritel(Fn1, regs + Resetctrl, 0); >+ microdelay(40); >+ } >+ cfgwritel(Fn1, regs + Ioctrl, 1|ioctl); >+ cfgreadl(Fn1, regs + Ioctrl); >+ if(SBDEBUG) print("%#lux %#lux\n", >+ cfgreadl(Fn1, regs+Ioctrl), cfgreadl(Fn1, regs+Resetctrl)); >+} >+ >+static void >+corescan(Ctlr *ctl, ulong r) >+{ >+ uchar *buf; >+ int i, coreid, corerev; >+ ulong addr; >+ >+ buf =3D sdmalloc(Corescansz); >+ if(buf =3D=3D nil) >+ error(Enomem); >+ sbmem(0, buf, Corescansz, r); >+ coreid =3D 0; >+ corerev =3D 0; >+ for(i =3D 0; i < Corescansz; i +=3D 4){ >+ switch(buf[i]&0xF){ >+ case 0xF: /* end */ >+ sdfree(buf); >+ return; >+ case 0x1: /* core info */ >+ if((buf[i+4]&0xF) !=3D 0x1) >+ break; >+ coreid =3D (buf[i+1] | buf[i+2]<<8) & 0xFFF; >+ i +=3D 4; >+ corerev =3D buf[i+3]; >+ break; >+ case 0x05: /* address */ >+ addr =3D buf[i+1]<<8 | buf[i+2]<<16 | buf[i+3]<<24; >+ addr &=3D ~0xFFF; >+ if(SBDEBUG) print("core %x %s %#lux\n", coreid, buf[i]&0xC0? "ctl" : = "mem", addr); >+ switch(coreid){ >+ case 0x800: >+ if((buf[i] & 0xC0) =3D=3D 0) >+ ctl->chipcommon =3D addr; >+ break; >+ case ARMcm3: >+ case ARM7tdmi: >+ case ARMcr4: >+ ctl->armcore =3D coreid; >+ if(buf[i] & 0xC0){ >+ if(ctl->armctl =3D=3D 0) >+ ctl->armctl =3D addr; >+ }else{ >+ if(ctl->armregs =3D=3D 0) >+ ctl->armregs =3D addr; >+ } >+ break; >+ case 0x80E: >+ if(buf[i] & 0xC0) >+ ctl->socramctl =3D addr; >+ else if(ctl->socramregs =3D=3D 0) >+ ctl->socramregs =3D addr; >+ ctl->socramrev =3D corerev; >+ break; >+ case 0x829: >+ if((buf[i] & 0xC0) =3D=3D 0) >+ ctl->sdregs =3D addr; >+ ctl->sdiorev =3D corerev; >+ break; >+ case 0x812: >+ if(buf[i] & 0xC0) >+ ctl->d11ctl =3D addr; >+ break; >+ } >+ } >+ } >+ sdfree(buf); >+} >+ >+static void >+ramscan(Ctlr *ctl) >+{ >+ ulong r, n, size; >+ int banks, i; >+ >+ if(ctl->armcore =3D=3D ARMcr4){ >+ r =3D ctl->armregs; >+ sbwindow(r); >+ n =3D cfgreadl(Fn1, r + Cr4Cap); >+ if(SBDEBUG) print("cr4 banks %lux\n", n); >+ banks =3D ((n>>4) & 0xF) + (n & 0xF); >+ size =3D 0; >+ for(i =3D 0; i < banks; i++){ >+ cfgwritel(Fn1, r + Cr4Bankidx, i); >+ n =3D cfgreadl(Fn1, r + Cr4Bankinfo); >+ if(SBDEBUG) print("bank %d reg %lux size %lud\n", i, n, 8192 * ((n & = 0x3F) + 1)); >+ size +=3D 8192 * ((n & 0x3F) + 1); >+ } >+ ctl->socramsize =3D size; >+ ctl->rambase =3D 0x198000; >+ return; >+ } >+ if(ctl->socramrev <=3D 7 || ctl->socramrev =3D=3D 12){ >+ print("ether4330: SOCRAM rev %d not supported\n", ctl->socramrev); >+ error(Eio); >+ } >+ sbreset(ctl->socramctl, 0, 0); >+ r =3D ctl->socramregs; >+ sbwindow(r); >+ n =3D cfgreadl(Fn1, r + Coreinfo); >+ if(SBDEBUG) print("socramrev %d coreinfo %lux\n", ctl->socramrev, n); >+ banks =3D (n>>4) & 0xF; >+ size =3D 0; >+ for(i =3D 0; i < banks; i++){ >+ cfgwritel(Fn1, r + Bankidx, i); >+ n =3D cfgreadl(Fn1, r + Bankinfo); >+ if(SBDEBUG) print("bank %d reg %lux size %lud\n", i, n, 8192 * ((n & 0= x3F) + 1)); >+ size +=3D 8192 * ((n & 0x3F) + 1); >+ } >+ ctl->socramsize =3D size; >+ ctl->rambase =3D 0; >+ if(ctl->chipid =3D=3D 43430){ >+ cfgwritel(Fn1, r + Bankidx, 3); >+ cfgwritel(Fn1, r + Bankpda, 0); >+ } >+} >+ >+static void >+sbinit(Ctlr *ctl) >+{ >+ ulong r; >+ int chipid; >+ char buf[16]; >+ >+ sbwindow(Enumbase); >+ r =3D cfgreadl(Fn1, Enumbase); >+ chipid =3D r & 0xFFFF; >+ sprint(buf, chipid > 43000 ? "%d" : "%#x", chipid); >+ print("ether4330: chip %s rev %ld type %ld\n", buf, (r>>16)&0xF, (r>>28= )&0xF); >+ switch(chipid){ >+ case 0x4330: >+ case 43362: >+ case 43430: >+ case 0x4345: >+ ctl->chipid =3D chipid; >+ ctl->chiprev =3D (r>>16)&0xF; >+ break; >+ default: >+ print("ether4330: chipid %#x (%d) not supported\n", chipid, chipid); >+ error(Eio); >+ } >+ r =3D cfgreadl(Fn1, Enumbase + 63*4); >+ corescan(ctl, r); >+ if(ctl->armctl =3D=3D 0 || ctl->d11ctl =3D=3D 0 || >+ (ctl->armcore =3D=3D ARMcm3 && (ctl->socramctl =3D=3D 0 || ctl->socr= amregs =3D=3D 0))) >+ error("corescan didn't find essential cores\n"); >+ if(ctl->armcore =3D=3D ARMcr4) >+ sbreset(ctl->armctl, Cr4Cpuhalt, Cr4Cpuhalt); >+ else=09 >+ sbdisable(ctl->armctl, 0, 0); >+ sbreset(ctl->d11ctl, 8|4, 4); >+ ramscan(ctl); >+ if(SBDEBUG) print("ARM %#lux D11 %#lux SOCRAM %#lux,%#lux %lud bytes @ = %#lux\n", >+ ctl->armctl, ctl->d11ctl, ctl->socramctl, ctl->socramregs, ctl->socram= size, ctl->rambase); >+ cfgw(Clkcsr, 0); >+ microdelay(10); >+ if(SBDEBUG) print("chipclk: %x\n", cfgr(Clkcsr)); >+ cfgw(Clkcsr, Nohwreq | ReqALP); >+ while((cfgr(Clkcsr) & (HTavail|ALPavail)) =3D=3D 0) >+ microdelay(10); >+ cfgw(Clkcsr, Nohwreq | ForceALP); >+ microdelay(65); >+ if(SBDEBUG) print("chipclk: %x\n", cfgr(Clkcsr)); >+ cfgw(Pullups, 0); >+ sbwindow(ctl->chipcommon); >+ cfgwritel(Fn1, ctl->chipcommon + Gpiopullup, 0); >+ cfgwritel(Fn1, ctl->chipcommon + Gpiopulldown, 0); >+ if(ctl->chipid !=3D 0x4330 && ctl->chipid !=3D 43362) >+ return; >+ cfgwritel(Fn1, ctl->chipcommon + Chipctladdr, 1); >+ if(cfgreadl(Fn1, ctl->chipcommon + Chipctladdr) !=3D 1) >+ print("ether4330: can't set Chipctladdr\n"); >+ else{ >+ r =3D cfgreadl(Fn1, ctl->chipcommon + Chipctldata); >+ if(SBDEBUG) print("chipcommon PMU (%lux) %lux", cfgreadl(Fn1, ctl->chi= pcommon + Chipctladdr), r); >+ /* set SDIO drive strength >=3D 6mA */ >+ r &=3D ~0x3800; >+ if(ctl->chipid =3D=3D 0x4330) >+ r |=3D 3<<11; >+ else >+ r |=3D 7<<11; >+ cfgwritel(Fn1, ctl->chipcommon + Chipctldata, r); >+ if(SBDEBUG) print("-> %lux (=3D %lux)\n", r, cfgreadl(Fn1, ctl->chipco= mmon + Chipctldata)); >+ } >+} >+ >+static void >+sbenable(Ctlr *ctl) >+{ >+ int i; >+ >+ if(SBDEBUG) print("enabling HT clock=2E=2E=2E"); >+ cfgw(Clkcsr, 0); >+ delay(1); >+ cfgw(Clkcsr, ReqHT); >+ for(i =3D 0; (cfgr(Clkcsr) & HTavail) =3D=3D 0; i++){ >+ if(i =3D=3D 50){ >+ print("ether4330: can't enable HT clock: csr %x\n", cfgr(Clkcsr)); >+ error(Eio); >+ } >+ tsleep(&up->sleep, return0, nil, 100); >+ } >+ cfgw(Clkcsr, cfgr(Clkcsr) | ForceHT); >+ delay(10); >+ if(SBDEBUG) print("chipclk: %x\n", cfgr(Clkcsr)); >+ sbwindow(ctl->sdregs); >+ cfgwritel(Fn1, ctl->sdregs + Sbmboxdata, 4 << 16); /* protocol version = */ >+ cfgwritel(Fn1, ctl->sdregs + Intmask, FrameInt | MailboxInt | Fcchange)= ; >+ sdioset(Fn0, Ioenable, 1<+ for(i =3D 0; !(sdiord(Fn0, Ioready) & 1<+ if(i =3D=3D 10){ >+ print("ether4330: can't enable SDIO function 2 - ioready %x\n", sdior= d(Fn0, Ioready)); >+ error(Eio); >+ } >+ tsleep(&up->sleep, return0, nil, 100); >+ } >+ sdiowr(Fn0, Intenable, (1<+} >+ >+ >+/* >+ * Firmware and config file uploading >+ */ >+ >+/* >+ * Condense config file contents (in buffer buf with length n) >+ * to 'var=3Dvalue\0' list for firmware: >+ * - remove comments (starting with '#') and blank lines >+ * - remove carriage returns >+ * - convert newlines to nulls >+ * - mark end with two nulls >+ * - pad with nulls to multiple of 4 bytes total length >+ */ >+static int >+condense(uchar *buf, int n) >+{ >+ uchar *p, *ep, *lp, *op; >+ int c, skipping; >+ >+ skipping =3D 0; /* true if in a comment */ >+ ep =3D buf + n; /* end of input */ >+ op =3D buf; /* end of output */ >+ lp =3D buf; /* start of current output line */ >+ for(p =3D buf; p < ep; p++){ >+ switch(c =3D *p){ >+ case '#': >+ skipping =3D 1; >+ break; >+ case '\0': >+ case '\n': >+ skipping =3D 0; >+ if(op !=3D lp){ >+ *op++ =3D '\0'; >+ lp =3D op; >+ } >+ break; >+ case '\r': >+ break; >+ default: >+ if(!skipping) >+ *op++ =3D c; >+ break; >+ } >+ } >+ if(!skipping && op !=3D lp) >+ *op++ =3D '\0'; >+ *op++ =3D '\0'; >+ for(n =3D op - buf; n & 03; n++) >+ *op++ =3D '\0'; >+ return n; >+} >+ >+/* >+ * Try to find firmware file in /boot or in /lib/firmware=2E >+ * Throw an error if not found=2E >+ */ >+static Chan* >+findfirmware(char *file) >+{ >+ char nbuf[64]; >+ Chan *c; >+ >+ if(!waserror()){ >+ snprint(nbuf, sizeof nbuf, "/boot/%s", file); >+ c =3D namec(nbuf, Aopen, OREAD, 0); >+ poperror(); >+ }else if(!waserror()){ >+ snprint(nbuf, sizeof nbuf, "/lib/firmware/%s", file); >+ c =3D namec(nbuf, Aopen, OREAD, 0); >+ poperror(); >+ }else{ >+ c =3D nil; >+ snprint(up->genbuf, sizeof up->genbuf, "can't find %s in /boot or /lib= /firmware", file); >+ error(up->genbuf); >+ } >+ return c;=09 >+} >+ >+static int >+upload(Ctlr *ctl, char *file, int isconfig) >+{ >+ Chan *c; >+ uchar *buf; >+ uchar *cbuf; >+ int off, n; >+ >+ buf =3D cbuf =3D nil; >+ c =3D findfirmware(file); >+ if(waserror()){ >+ cclose(c); >+ sdfree(buf); >+ sdfree(cbuf); >+ nexterror(); >+ } >+ buf =3D sdmalloc(Uploadsz); >+ if(buf =3D=3D nil) >+ error(Enomem); >+ if(Firmwarecmp){ >+ cbuf =3D sdmalloc(Uploadsz); >+ if(cbuf =3D=3D nil) >+ error(Enomem); >+ } >+ off =3D 0; >+ for(;;){ >+ n =3D devtab[c->type]->read(c, buf, Uploadsz, off); >+ if(n <=3D 0) >+ break; >+ if(isconfig){ >+ n =3D condense(buf, n); >+ off =3D ctl->socramsize - n - 4; >+ }else if(off =3D=3D 0) >+ memmove(ctl->resetvec=2Ec, buf, sizeof(ctl->resetvec=2Ec)); >+ while(n&3) >+ buf[n++] =3D 0; >+ sbmem(1, buf, n, ctl->rambase + off); >+ if(isconfig) >+ break; >+ off +=3D n; >+ } >+ if(Firmwarecmp){ >+ if(FWDEBUG) print("compare=2E=2E=2E"); >+ if(!isconfig) >+ off =3D 0; >+ for(;;){ >+ if(!isconfig){ >+ n =3D devtab[c->type]->read(c, buf, Uploadsz, off); >+ if(n <=3D 0) >+ break; >+ while(n&3) >+ buf[n++] =3D 0; >+ } >+ sbmem(0, cbuf, n, ctl->rambase + off); >+ if(memcmp(buf, cbuf, n) !=3D 0){ >+ print("ether4330: firmware load failed offset %d\n", off); >+ error(Eio); >+ } >+ if(isconfig) >+ break; >+ off +=3D n; >+ } >+ } >+ if(FWDEBUG) print("\n"); >+ poperror(); >+ cclose(c); >+ sdfree(buf); >+ sdfree(cbuf); >+ return n; >+} >+ >+/* >+ * Upload regulatory file (=2Eclm) to firmware=2E >+ * Packet format is >+ * [2]flag [2]type [4]len [4]crc [len]data >+ */ >+static void >+reguload(Ctlr *ctl, char *file) >+{ >+ Chan *c; >+ uchar *buf; >+ int off, n, flag; >+ enum { >+ Reguhdr =3D 2+2+4+4, >+ Regusz =3D 1400, >+ Regutyp =3D 2, >+ Flagclm =3D 1<<12, >+ Firstpkt=3D 1<<1, >+ Lastpkt =3D 1<<2, >+ }; >+ >+ buf =3D nil; >+ c =3D findfirmware(file); >+ if(waserror()){ >+ cclose(c); >+ free(buf); >+ nexterror(); >+ } >+ buf =3D malloc(Reguhdr+Regusz+1); >+ if(buf =3D=3D nil) >+ error(Enomem); >+ put2(buf+2, Regutyp); >+ put2(buf+8, 0); >+ off =3D 0; >+ flag =3D Flagclm | Firstpkt; >+ while((flag&Lastpkt) =3D=3D 0){ >+ n =3D devtab[c->type]->read(c, buf+Reguhdr, Regusz+1, off); >+ if(n <=3D 0) >+ break; >+ if(n =3D=3D Regusz+1) >+ --n; >+ else{ >+ while(n&7) >+ buf[Reguhdr+n++] =3D 0; >+ flag |=3D Lastpkt; >+ } >+ put2(buf+0, flag); >+ put4(buf+4, n); >+ wlsetvar(ctl, "clmload", buf, Reguhdr + n); >+ off +=3D n; >+ flag &=3D ~Firstpkt; >+ } >+ poperror(); >+ cclose(c); >+ free(buf); >+} >+ >+static void >+fwload(Ctlr *ctl) >+{ >+ uchar buf[4]; >+ uint i, n; >+ >+ i =3D 0; >+ while(firmware[i]=2Echipid !=3D ctl->chipid || >+ firmware[i]=2Echiprev !=3D ctl->chiprev){ >+ if(++i =3D=3D nelem(firmware)){ >+ print("ether4330: no firmware for chipid %x (%d) chiprev %d\n", >+ ctl->chipid, ctl->chipid, ctl->chiprev); >+ error("no firmware"); >+ } >+ } >+ ctl->regufile =3D firmware[i]=2Eregufile; >+ cfgw(Clkcsr, ReqALP); >+ while((cfgr(Clkcsr) & ALPavail) =3D=3D 0) >+ microdelay(10); >+ memset(buf, 0, 4); >+ sbmem(1, buf, 4, ctl->rambase + ctl->socramsize - 4); >+ if(FWDEBUG) print("firmware load=2E=2E=2E"); >+ upload(ctl, firmware[i]=2Efwfile, 0); >+ if(FWDEBUG) print("config load=2E=2E=2E"); >+ n =3D upload(ctl, firmware[i]=2Ecfgfile, 1); >+ n /=3D 4; >+ n =3D (n & 0xFFFF) | (~n << 16); >+ put4(buf, n); >+ sbmem(1, buf, 4, ctl->rambase + ctl->socramsize - 4); >+ if(ctl->armcore =3D=3D ARMcr4){ >+ sbwindow(ctl->sdregs); >+ cfgwritel(Fn1, ctl->sdregs + Intstatus, ~0); >+ if(ctl->resetvec=2Ei !=3D 0){ >+ if(SBDEBUG) print("%ux\n", ctl->resetvec=2Ei); >+ sbmem(1, ctl->resetvec=2Ec, sizeof(ctl->resetvec=2Ec), 0); >+ } >+ sbreset(ctl->armctl, Cr4Cpuhalt, 0); >+ }else >+ sbreset(ctl->armctl, 0, 0); >+} >+ >+/* >+ * Communication of data and control packets >+ */ >+ >+void >+intwait(Ctlr *ctlr, int wait) >+{ >+ ulong ints, mbox; >+ int i; >+ >+ if(waserror()) >+ return; >+ for(;;){ >+ sdiocardintr(wait); >+ sbwindow(ctlr->sdregs); >+ i =3D sdiord(Fn0, Intpend); >+ if(i =3D=3D 0){ >+ tsleep(&up->sleep, return0, 0, 10); >+ continue; >+ } >+ ints =3D cfgreadl(Fn1, ctlr->sdregs + Intstatus); >+ cfgwritel(Fn1, ctlr->sdregs + Intstatus, ints); >+ if(0) print("INTS: (%x) %lux -> %lux\n", i, ints, cfgreadl(Fn1, ctlr->= sdregs + Intstatus)); >+ if(ints & MailboxInt){ >+ mbox =3D cfgreadl(Fn1, ctlr->sdregs + Hostmboxdata); >+ cfgwritel(Fn1, ctlr->sdregs + Sbmbox, 2); /* ack */ >+ if(mbox & 0x8) >+ print("ether4330: firmware ready\n"); >+ } >+ if(ints & FrameInt) >+ break; >+ } >+ poperror(); >+} >+ >+static Block* >+wlreadpkt(Ctlr *ctl) >+{ >+ Block *b; >+ Sdpcm *p; >+ int len, lenck; >+ >+ b =3D allocb(2048); >+ p =3D (Sdpcm*)b->wp; >+ qlock(&ctl->pktlock); >+ for(;;){ >+ packetrw(0, b->wp, Sdpcmsz); >+ len =3D p->len[0] | p->len[1]<<8; >+ if(len =3D=3D 0){ >+ freeb(b); >+ b =3D nil; >+ break; >+ } >+ lenck =3D p->lenck[0] | p->lenck[1]<<8; >+ if(lenck !=3D (len ^ 0xFFFF) || >+ len < Sdpcmsz || len > 2048){ >+ print("ether4330: wlreadpkt error len %=2E4x lenck %=2E4x\n", len, le= nck); >+ cfgw(Framectl, Rfhalt); >+ while(cfgr(Rfrmcnt+1)) >+ ; >+ while(cfgr(Rfrmcnt)) >+ ; >+ continue; >+ } >+ if(len > Sdpcmsz) >+ packetrw(0, b->wp + Sdpcmsz, len - Sdpcmsz); >+ b->wp +=3D len; >+ break; >+ } >+ qunlock(&ctl->pktlock); >+ return b; >+} >+ >+static void >+txstart(Ether *edev) >+{ >+ Ctlr *ctl; >+ Sdpcm *p; >+ Block *b; >+ int len, off; >+ >+ ctl =3D edev->ctlr; >+ if(!canqlock(&ctl->tlock)) >+ return; >+ if(waserror()){ >+ qunlock(&ctl->tlock); >+ return; >+ } >+ for(;;){ >+ lock(&ctl->txwinlock); >+ if(ctl->txseq =3D=3D ctl->txwindow){ >+ //print("f"); >+ unlock(&ctl->txwinlock); >+ break; >+ } >+ if(ctl->fcmask & 1<<2){ >+ //print("x"); >+ unlock(&ctl->txwinlock); >+ break; >+ } >+ unlock(&ctl->txwinlock); >+ b =3D qget(edev->oq); >+ if(b =3D=3D nil) >+ break; >+ off =3D ((uintptr)b->rp & 3) + Sdpcmsz; >+ b =3D padblock(b, off + 4); >+ len =3D BLEN(b); >+ p =3D (Sdpcm*)b->rp; >+ memset(p, 0, off); /* TODO: refactor dup code */ >+ put2(p->len, len); >+ put2(p->lenck, ~len); >+ p->chanflg =3D 2; >+ p->seq =3D ctl->txseq; >+ p->doffset =3D off; >+ put4(b->rp + off, 0x20); /* BDC header */ >+ if(iodebug) dump("send", b->rp, len); >+ qlock(&ctl->pktlock); >+ if(waserror()){ >+ if(iodebug) print("halt frame %x %x\n", cfgr(Wfrmcnt+1), cfgr(Wfrmcnt= +1)); >+ cfgw(Framectl, Wfhalt); >+ while(cfgr(Wfrmcnt+1)) >+ ; >+ while(cfgr(Wfrmcnt)) >+ ; >+ qunlock(&ctl->pktlock); >+ nexterror(); >+ } >+ packetrw(1, b->rp, len); >+ ctl->txseq++; >+ poperror(); >+ qunlock(&ctl->pktlock); >+ freeb(b); >+ } >+ poperror(); >+ qunlock(&ctl->tlock); >+} >+ >+static void >+rproc(void *a) >+{ >+ Ether *edev; >+ Ctlr *ctl; >+ Block *b; >+ Sdpcm *p; >+ Cmd *q; >+ int flowstart; >+ int bdc; >+ >+ edev =3D a; >+ ctl =3D edev->ctlr; >+ flowstart =3D 0; >+ for(;;){ >+ if(flowstart){ >+ //print("F"); >+ flowstart =3D 0; >+ txstart(edev); >+ } >+ b =3D wlreadpkt(ctl); >+ if(b =3D=3D nil){ >+ intwait(ctl, 1); >+ continue; >+ } >+ p =3D (Sdpcm*)b->rp; >+ if(p->window !=3D ctl->txwindow || p->fcmask !=3D ctl->fcmask){ >+ lock(&ctl->txwinlock); >+ if(p->window !=3D ctl->txwindow){ >+ if(ctl->txseq =3D=3D ctl->txwindow) >+ flowstart =3D 1; >+ ctl->txwindow =3D p->window; >+ } >+ if(p->fcmask !=3D ctl->fcmask){ >+ if((p->fcmask & 1<<2) =3D=3D 0) >+ flowstart =3D 1; >+ ctl->fcmask =3D p->fcmask; >+ } >+ unlock(&ctl->txwinlock); >+ } >+ switch(p->chanflg & 0xF){ >+ case 0: >+ if(iodebug) dump("rsp", b->rp, BLEN(b)); >+ if(BLEN(b) < Sdpcmsz + Cmdsz) >+ break; >+ q =3D (Cmd*)(b->rp + Sdpcmsz); >+ if((q->id[0] | q->id[1]<<8) !=3D ctl->reqid) >+ break; >+ ctl->rsp =3D b; >+ wakeup(&ctl->cmdr); >+ continue; >+ case 1: >+ if(iodebug) dump("event", b->rp, BLEN(b)); >+ if(BLEN(b) > p->doffset + 4){ >+ bdc =3D 4 + (b->rp[p->doffset + 3] << 2); >+ if(BLEN(b) > p->doffset + bdc){ >+ b->rp +=3D p->doffset + bdc; /* skip BDC header */ >+ bcmevent(ctl, b->rp, BLEN(b)); >+ break; >+ } >+ } >+ if(iodebug && BLEN(b) !=3D p->doffset) >+ print("short event %lld %d\n", BLEN(b), p->doffset); >+ break; >+ case 2: >+ if(iodebug) dump("packet", b->rp, BLEN(b)); >+ if(BLEN(b) > p->doffset + 4){ >+ bdc =3D 4 + (b->rp[p->doffset + 3] << 2); >+ if(BLEN(b) >=3D p->doffset + bdc + ETHERHDRSIZE){ >+ b->rp +=3D p->doffset + bdc; /* skip BDC header */ >+ etheriq(edev, b); >+ continue; >+ } >+ } >+ break; >+ default: >+ dump("ether4330: bad packet", b->rp, BLEN(b)); >+ break; >+ } >+ freeb(b); >+ } >+} >+ >+static void >+linkdown(Ctlr *ctl) >+{ >+ Ether *edev; >+ Netfile *f; >+ int i; >+ >+ edev =3D ctl->edev; >+ if(edev =3D=3D nil || ctl->status !=3D Connected) >+ return; >+ ctl->status =3D Disconnected; >+ /* send eof to aux/wpa */ >+ for(i =3D 0; i < edev->nfile; i++){ >+ f =3D edev->f[i]; >+ if(f =3D=3D nil || f->in =3D=3D nil || f->inuse =3D=3D 0 || f->type != =3D 0x888e) >+ continue; >+ qwrite(f->in, 0, 0); >+ } >+} >+ >+/* >+ * Command interface between host and firmware >+ */ >+ >+static char *eventnames[] =3D { >+ [0] =3D "set ssid", >+ [1] =3D "join", >+ [2] =3D "start", >+ [3] =3D "auth", >+ [4] =3D "auth ind", >+ [5] =3D "deauth", >+ [6] =3D "deauth ind", >+ [7] =3D "assoc", >+ [8] =3D "assoc ind", >+ [9] =3D "reassoc", >+ [10] =3D "reassoc ind", >+ [11] =3D "disassoc", >+ [12] =3D "disassoc ind", >+ [13] =3D "quiet start", >+ [14] =3D "quiet end", >+ [15] =3D "beacon rx", >+ [16] =3D "link", >+ [17] =3D "mic error", >+ [18] =3D "ndis link", >+ [19] =3D "roam", >+ [20] =3D "txfail", >+ [21] =3D "pmkid cache", >+ [22] =3D "retrograde tsf", >+ [23] =3D "prune", >+ [24] =3D "autoauth", >+ [25] =3D "eapol msg", >+ [26] =3D "scan complete", >+ [27] =3D "addts ind", >+ [28] =3D "delts ind", >+ [29] =3D "bcnsent ind", >+ [30] =3D "bcnrx msg", >+ [31] =3D "bcnlost msg", >+ [32] =3D "roam prep", >+ [33] =3D "pfn net found", >+ [34] =3D "pfn net lost", >+ [35] =3D "reset complete", >+ [36] =3D "join start", >+ [37] =3D "roam start", >+ [38] =3D "assoc start", >+ [39] =3D "ibss assoc", >+ [40] =3D "radio", >+ [41] =3D "psm watchdog", >+ [44] =3D "probreq msg", >+ [45] =3D "scan confirm ind", >+ [46] =3D "psk sup", >+ [47] =3D "country code changed", >+ [48] =3D "exceeded medium time", >+ [49] =3D "icv error", >+ [50] =3D "unicast decode error", >+ [51] =3D "multicast decode error", >+ [52] =3D "trace", >+ [53] =3D "bta hci event", >+ [54] =3D "if", >+ [55] =3D "p2p disc listen complete", >+ [56] =3D "rssi", >+ [57] =3D "pfn scan complete", >+ [58] =3D "extlog msg", >+ [59] =3D "action frame", >+ [60] =3D "action frame complete", >+ [61] =3D "pre assoc ind", >+ [62] =3D "pre reassoc ind", >+ [63] =3D "channel adopted", >+ [64] =3D "ap started", >+ [65] =3D "dfs ap stop", >+ [66] =3D "dfs ap resume", >+ [67] =3D "wai sta event", >+ [68] =3D "wai msg", >+ [69] =3D "escan result", >+ [70] =3D "action frame off chan complete", >+ [71] =3D "probresp msg", >+ [72] =3D "p2p probreq msg", >+ [73] =3D "dcs request", >+ [74] =3D "fifo credit map", >+ [75] =3D "action frame rx", >+ [76] =3D "wake event", >+ [77] =3D "rm complete", >+ [78] =3D "htsfsync", >+ [79] =3D "overlay req", >+ [80] =3D "csa complete ind", >+ [81] =3D "excess pm wake event", >+ [82] =3D "pfn scan none", >+ [83] =3D "pfn scan allgone", >+ [84] =3D "gtk plumbed", >+ [85] =3D "assoc ind ndis", >+ [86] =3D "reassoc ind ndis", >+ [87] =3D "assoc req ie", >+ [88] =3D "assoc resp ie", >+ [89] =3D "assoc recreated", >+ [90] =3D "action frame rx ndis", >+ [91] =3D "auth req", >+ [92] =3D "tdls peer event", >+ [127] =3D "bcmc credit support" >+}; >+ >+static char* >+evstring(uint event) >+{ >+ static char buf[12]; >+ >+ if(event >=3D nelem(eventnames) || eventnames[event] =3D=3D 0){ >+ /* not reentrant but only called from one kproc */ >+ snprint(buf, sizeof buf, "%d", event); >+ return buf; >+ } >+ return eventnames[event]; >+} >+ >+static void >+bcmevent(Ctlr *ctl, uchar *p, int len) >+{ >+ int flags; >+ long event, status, reason; >+ >+ if(len < ETHERHDRSIZE + 10 + 46) >+ return; >+ p +=3D ETHERHDRSIZE + 10; /* skip bcm_ether header */ >+ len -=3D ETHERHDRSIZE + 10; >+ flags =3D nhgets(p + 2); >+ event =3D nhgets(p + 6); >+ status =3D nhgetl(p + 8); >+ reason =3D nhgetl(p + 12); >+ if(EVENTDEBUG) >+ print("ether4330: [%s] status %ld flags %#x reason %ld\n",=20 >+ evstring(event), status, flags, reason); >+ switch(event){ >+ case 19: /* E_ROAM */ >+ if(status =3D=3D 0) >+ break; >+ /* fall through */ >+ case 0: /* E_SET_SSID */ >+ ctl->joinstatus =3D 1 + status; >+ wakeup(&ctl->joinr); >+ break; >+ case 16: /* E_LINK */ >+ if(flags&1) /* link up */ >+ break; >+ /* fall through */ >+ case 5: /* E_DEAUTH */ >+ case 6: /* E_DEAUTH_IND */ >+ case 12: /* E_DISASSOC_IND */ >+ linkdown(ctl); >+ break; >+ case 26: /* E_SCAN_COMPLETE */ >+ break; >+ case 69: /* E_ESCAN_RESULT */ >+ wlscanresult(ctl->edev, p + 48, len - 48); >+ break; >+ default: >+ if(status){ >+ if(!EVENTDEBUG) >+ print("ether4330: [%s] error status %ld flags %#x reason %ld\n", >+ evstring(event), status, flags, reason); >+ dump("event", p, len); >+ } >+ } >+} >+ >+static int >+joindone(void *a) >+{ >+ return ((Ctlr*)a)->joinstatus; >+} >+ >+static int >+waitjoin(Ctlr *ctl) >+{ >+ int n; >+ >+ sleep(&ctl->joinr, joindone, ctl); >+ n =3D ctl->joinstatus; >+ ctl->joinstatus =3D 0; >+ return n - 1; >+} >+ >+static int >+cmddone(void *a) >+{ >+ return ((Ctlr*)a)->rsp !=3D nil; >+} >+ >+static void >+wlcmd(Ctlr *ctl, int write, int op, void *data, int dlen, void *res, int= rlen) >+{ >+ Block *b; >+ Sdpcm *p; >+ Cmd *q; >+ int len, tlen; >+ >+ if(write) >+ tlen =3D dlen + rlen; >+ else >+ tlen =3D MAX(dlen, rlen); >+ len =3D Sdpcmsz + Cmdsz + tlen; >+ b =3D allocb(len); >+ qlock(&ctl->cmdlock); >+ if(waserror()){ >+ freeb(b); >+ qunlock(&ctl->cmdlock); >+ nexterror(); >+ } >+ memset(b->wp, 0, len); >+ qlock(&ctl->pktlock); >+ p =3D (Sdpcm*)b->wp; >+ put2(p->len, len); >+ put2(p->lenck, ~len); >+ p->seq =3D ctl->txseq; >+ p->doffset =3D Sdpcmsz; >+ b->wp +=3D Sdpcmsz; >+=09 >+ q =3D (Cmd*)b->wp; >+ put4(q->cmd, op); >+ put4(q->len, tlen); >+ put2(q->flags, write? 2 : 0); >+ put2(q->id, ++ctl->reqid); >+ put4(q->status, 0); >+ b->wp +=3D Cmdsz; >+ >+ if(dlen > 0) >+ memmove(b->wp, data, dlen); >+ if(write) >+ memmove(b->wp + dlen, res, rlen); >+ b->wp +=3D tlen; >+ >+ if(iodebug) dump("cmd", b->rp, len); >+ packetrw(1, b->rp, len); >+ ctl->txseq++; >+ qunlock(&ctl->pktlock); >+ freeb(b); >+ b =3D nil; >+ USED(b); >+ sleep(&ctl->cmdr, cmddone, ctl); >+ b =3D ctl->rsp; >+ ctl->rsp =3D nil; >+ assert(b !=3D nil); >+ p =3D (Sdpcm*)b->rp; >+ q =3D (Cmd*)(b->rp + p->doffset); >+ if(q->status[0] | q->status[1] | q->status[2] | q->status[3]){ >+ print("ether4330: cmd %d error status %ld\n", op, get4(q->status)); >+ dump("ether4330: cmd error", b->rp, BLEN(b)); >+ error("wlcmd error"); >+ } >+ if(!write) >+ memmove(res, q + 1, rlen); >+ freeb(b); >+ qunlock(&ctl->cmdlock); >+ poperror(); >+} >+ >+static void >+wlcmdint(Ctlr *ctl, int op, int val) >+{ >+ uchar buf[4]; >+ >+ put4(buf, val); >+ wlcmd(ctl, 1, op, buf, 4, nil, 0); >+} >+ >+static void >+wlgetvar(Ctlr *ctl, char *name, void *val, int len) >+{ >+ wlcmd(ctl, 0, GetVar, name, strlen(name) + 1, val, len); >+} >+ >+static void >+wlsetvar(Ctlr *ctl, char *name, void *val, int len) >+{ >+ if(VARDEBUG){ >+ char buf[32]; >+ snprint(buf, sizeof buf, "wlsetvar %s:", name); >+ dump(buf, val, len); >+ } >+ wlcmd(ctl, 1, SetVar, name, strlen(name) + 1, val, len); >+} >+ >+static void >+wlsetint(Ctlr *ctl, char *name, int val) >+{ >+ uchar buf[4]; >+ >+ put4(buf, val); >+ wlsetvar(ctl, name, buf, 4); >+} >+ >+static void >+wlwepkey(Ctlr *ctl, int i) >+{ >+ uchar params[164]; >+ uchar *p; >+ >+ memset(params, 0, sizeof params); >+ p =3D params; >+ p =3D put4(p, i); /* index */ >+ p =3D put4(p, ctl->keys[i]=2Elen); >+ memmove(p, ctl->keys[i]=2Edat, ctl->keys[i]=2Elen); >+ p +=3D 32 + 18*4; /* keydata, pad */ >+ if(ctl->keys[i]=2Elen =3D=3D WMinKeyLen) >+ p =3D put4(p, 1); /* algo =3D WEP1 */ >+ else >+ p =3D put4(p, 3); /* algo =3D WEP128 */ >+ put4(p, 2); /* flags =3D Primarykey */ >+ >+ wlsetvar(ctl, "wsec_key", params, sizeof params); >+} >+ >+static void >+memreverse(char *dst, char *src, int len) >+{ >+ src +=3D len; >+ while(len-- > 0) >+ *dst++ =3D *--src; >+} >+ >+static void >+wlwpakey(Ctlr *ctl, int id, uvlong iv, uchar *ea) >+{ >+ uchar params[164]; >+ uchar *p; >+ int pairwise; >+ >+ if(id =3D=3D CMrxkey) >+ return; >+ pairwise =3D (id =3D=3D CMrxkey || id =3D=3D CMtxkey); >+ memset(params, 0, sizeof params); >+ p =3D params; >+ if(pairwise) >+ p =3D put4(p, 0); >+ else >+ p =3D put4(p, id - CMrxkey0); /* group key id */ >+ p =3D put4(p, ctl->keys[0]=2Elen); >+ memmove((char*)p, ctl->keys[0]=2Edat, ctl->keys[0]=2Elen); >+ p +=3D 32 + 18*4; /* keydata, pad */ >+ if(ctl->cryptotype =3D=3D Wpa) >+ p =3D put4(p, 2); /* algo =3D TKIP */ >+ else >+ p =3D put4(p, 4); /* algo =3D AES_CCM */ >+ if(pairwise) >+ p =3D put4(p, 0); >+ else >+ p =3D put4(p, 2); /* flags =3D Primarykey */ >+ p +=3D 3*4; >+ p =3D put4(p, 0); //pairwise); /* iv initialised */ >+ p +=3D 4; >+ p =3D put4(p, iv>>16); /* iv high */ >+ p =3D put2(p, iv&0xFFFF); /* iv low */ >+ p +=3D 2 + 2*4; /* align, pad */ >+ if(pairwise) >+ memmove(p, ea, Eaddrlen); >+ >+ wlsetvar(ctl, "wsec_key", params, sizeof params); >+} >+ >+static void >+wljoin(Ctlr *ctl, char *ssid, int chan) >+{ >+ uchar params[72]; >+ uchar *p; >+ int n; >+ >+ if(chan !=3D 0) >+ chan |=3D 0x2b00; /* 20Mhz channel width */ >+ p =3D params; >+ n =3D strlen(ssid); >+ n =3D MIN(n, 32); >+ p =3D put4(p, n); >+ memmove(p, ssid, n); >+ memset(p + n, 0, 32 - n); >+ p +=3D 32; >+ p =3D put4(p, 0xff); /* scan type */ >+ if(chan !=3D 0){ >+ p =3D put4(p, 2); /* num probes */ >+ p =3D put4(p, 120); /* active time */ >+ p =3D put4(p, 390); /* passive time */ >+ }else{ >+ p =3D put4(p, -1); /* num probes */ >+ p =3D put4(p, -1); /* active time */ >+ p =3D put4(p, -1); /* passive time */ >+ } >+ p =3D put4(p, -1); /* home time */ >+ memset(p, 0xFF, Eaddrlen); /* bssid */ >+ p +=3D Eaddrlen; >+ p =3D put2(p, 0); /* pad */ >+ if(chan !=3D 0){ >+ p =3D put4(p, 1); /* num chans */ >+ p =3D put2(p, chan); /* chan spec */ >+ p =3D put2(p, 0); /* pad */ >+ assert(p =3D=3D params + sizeof(params)); >+ }else{ >+ p =3D put4(p, 0); /* num chans */ >+ assert(p =3D=3D params + sizeof(params) - 4); >+ } >+ >+ wlsetvar(ctl, "join", params, chan? sizeof params : sizeof params - 4); >+ ctl->status =3D Connecting; >+ switch(waitjoin(ctl)){ >+ case 0: >+ ctl->status =3D Connected; >+ break; >+ case 3: >+ ctl->status =3D Disconnected; >+ error("wifi join: network not found"); >+ case 1: >+ ctl->status =3D Disconnected; >+ error("wifi join: failed"); >+ default: >+ ctl->status =3D Disconnected; >+ error("wifi join: error"); >+ } >+} >+ >+static void >+wlscanstart(Ctlr *ctl) >+{ >+ /* version[4] action[2] sync_id[2] ssidlen[4] ssid[32] bssid[6] bss_typ= e[1] >+ scan_type[1] nprobes[4] active_time[4] passive_time[4] home_time[4] >+ nchans[2] nssids[2] chans[nchans][2] ssids[nssids][32] */ >+ /* hack - this is only correct on a little-endian cpu */ >+ static uchar params[4+2+2+4+32+6+1+1+4*4+2+2+14*2+32+4] =3D { >+ 1,0,0,0, >+ 1,0, >+ 0x34,0x12, >+ 0,0,0,0, >+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, >+ 0xff,0xff,0xff,0xff,0xff,0xff, >+ 2, >+ 0, >+ 0xff,0xff,0xff,0xff, >+ 0xff,0xff,0xff,0xff, >+ 0xff,0xff,0xff,0xff, >+ 0xff,0xff,0xff,0xff, >+ 14,0, >+ 1,0, >+ 0x01,0x2b,0x02,0x2b,0x03,0x2b,0x04,0x2b,0x05,0x2e,0x06,0x2e,0x07,0x2e, >+ 0x08,0x2b,0x09,0x2b,0x0a,0x2b,0x0b,0x2b,0x0c,0x2b,0x0d,0x2b,0x0e,0x2b, >+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, >+ }; >+ >+ wlcmdint(ctl, 49, 0); /* PASSIVE_SCAN */ >+ wlsetvar(ctl, "escan", params, sizeof params); >+} >+ >+static uchar* >+gettlv(uchar *p, uchar *ep, int tag) >+{ >+ int len; >+ >+ while(p + 1 < ep){ >+ len =3D p[1]; >+ if(p + 2 + len > ep) >+ return nil; >+ if(p[0] =3D=3D tag) >+ return p; >+ p +=3D 2 + len; >+ } >+ return nil; >+} >+ >+static void >+addscan(Block *bp, uchar *p, int len) >+{ >+ char bssid[24]; >+ char *auth, *auth2; >+ uchar *t, *et; >+ int ielen; >+ static uchar wpaie1[4] =3D { 0x00, 0x50, 0xf2, 0x01 }; >+ >+ snprint(bssid, sizeof bssid, ";bssid=3D%E", p + 8); >+ if(strstr((char*)bp->rp, bssid) !=3D nil) >+ return; >+ bp->wp =3D (uchar*)seprint((char*)bp->wp, (char*)bp->lim, >+ "ssid=3D%=2E*s%s;signal=3D%d;noise=3D%d;chan=3D%d", >+ p[18], (char*)p+19, bssid, >+ (short)get2(p+78), (signed char)p[80], >+ get2(p+72) & 0xF); >+ auth =3D auth2 =3D ""; >+ if(get2(p + 16) & 0x10) >+ auth =3D ";wep"; >+ ielen =3D get4(p + 0x78); >+ if(ielen > 0){ >+ t =3D p + get4(p + 0x74); >+ et =3D t + ielen; >+ if(et > p + len) >+ return; >+ if(gettlv(t, et, 0x30) !=3D nil){ >+ auth =3D ""; >+ auth2 =3D ";wpa2"; >+ } >+ while((t =3D gettlv(t, et, 0xdd)) !=3D nil){ >+ if(t[1] > 4 && memcmp(t+2, wpaie1, 4) =3D=3D 0){ >+ auth =3D ";wpa"; >+ break; >+ } >+ t +=3D 2 + t[1]; >+ } >+ } >+ bp->wp =3D (uchar*)seprint((char*)bp->wp, (char*)bp->lim, >+ "%s%s\n", auth, auth2); >+} >+ >+ >+static void >+wlscanresult(Ether *edev, uchar *p, int len) >+{ >+ Ctlr *ctlr; >+ Netfile **ep, *f, **fp; >+ Block *bp; >+ int nbss, i; >+ >+ ctlr =3D edev->ctlr; >+ if(get4(p) > len) >+ return; >+ /* TODO: more syntax checking */ >+ bp =3D ctlr->scanb; >+ if(bp =3D=3D nil) >+ ctlr->scanb =3D bp =3D allocb(8192); >+ nbss =3D get2(p+10); >+ p +=3D 12; >+ len -=3D 12; >+ if(0) dump("SCAN", p, len); >+ if(nbss){ >+ addscan(bp, p, len); >+ return; >+ } >+ i =3D edev->scan; >+ ep =3D &edev->f[Ntypes]; >+ for(fp =3D edev->f; fp < ep && i > 0; fp++){ >+ f =3D *fp; >+ if(f =3D=3D nil || f->scan =3D=3D 0) >+ continue; >+ if(i =3D=3D 1) >+ qpass(f->in, bp); >+ else >+ qpass(f->in, copyblock(bp, BLEN(bp))); >+ i--; >+ } >+ if(i) >+ freeb(bp); >+ ctlr->scanb =3D nil; >+} >+ >+static void >+lproc(void *a) >+{ >+ Ether *edev; >+ Ctlr *ctlr; >+ int secs; >+ >+ edev =3D a; >+ ctlr =3D edev->ctlr; >+ secs =3D 0; >+ for(;;){ >+ tsleep(&up->sleep, return0, 0, 1000); >+ if(ctlr->scansecs){ >+ if(secs =3D=3D 0){ >+ if(waserror()) >+ ctlr->scansecs =3D 0; >+ else{ >+ wlscanstart(ctlr); >+ poperror(); >+ } >+ secs =3D ctlr->scansecs; >+ } >+ --secs; >+ }else >+ secs =3D 0; >+ } >+} >+ >+static void >+wlinit(Ether *edev, Ctlr *ctlr) >+{ >+ uchar ea[Eaddrlen]; >+ uchar eventmask[16]; >+ char version[128]; >+ char *p; >+ static uchar keepalive[12] =3D {1, 0, 11, 0, 0xd8, 0xd6, 0, 0, 0, 0, 0,= 0}; >+ >+ wlgetvar(ctlr, "cur_etheraddr", ea, Eaddrlen); >+ memmove(edev->ea, ea, Eaddrlen); >+ memmove(edev->addr, ea, Eaddrlen); >+ print("ether4330: addr %E\n", edev->ea); >+ wlsetint(ctlr, "assoc_listen", 10); >+ if(ctlr->chipid =3D=3D 43430 || ctlr->chipid =3D=3D 0x4345) >+ wlcmdint(ctlr, 0x56, 0); /* powersave off */ >+ else >+ wlcmdint(ctlr, 0x56, 2); /* powersave FAST */ >+ wlsetint(ctlr, "bus:txglom", 0); >+ wlsetint(ctlr, "bcn_timeout", 10); >+ wlsetint(ctlr, "assoc_retry_max", 3); >+ if(ctlr->chipid =3D=3D 0x4330){ >+ wlsetint(ctlr, "btc_wire", 4); >+ wlsetint(ctlr, "btc_mode", 1); >+ wlsetvar(ctlr, "mkeep_alive", keepalive, 11); >+ } >+ memset(eventmask, 0xFF, sizeof eventmask); >+#define ENABLE(n) eventmask[n/8] |=3D 1<<(n%8) >+#define DISABLE(n) eventmask[n/8] &=3D ~(1<<(n%8)) >+ DISABLE(40); /* E_RADIO */ >+ DISABLE(44); /* E_PROBREQ_MSG */ >+ DISABLE(54); /* E_IF */ >+ DISABLE(71); /* E_PROBRESP_MSG */ >+ DISABLE(20); /* E_TXFAIL */ >+ DISABLE(124); /* ? */ >+ wlsetvar(ctlr, "event_msgs", eventmask, sizeof eventmask); >+ wlcmdint(ctlr, 0xb9, 0x28); /* SET_SCAN_CHANNEL_TIME */ >+ wlcmdint(ctlr, 0xbb, 0x28); /* SET_SCAN_UNASSOC_TIME */ >+ wlcmdint(ctlr, 0x102, 0x82); /* SET_SCAN_PASSIVE_TIME */ >+ wlcmdint(ctlr, 2, 0); /* UP */ >+ memset(version, 0, sizeof version); >+ wlgetvar(ctlr, "ver", version, sizeof version - 1); >+ if((p =3D strchr(version, '\n')) !=3D nil) >+ *p =3D '\0'; >+ if(0) print("ether4330: %s\n", version); >+ wlsetint(ctlr, "roam_off", 1); >+ wlcmdint(ctlr, 0x14, 1); /* SET_INFRA 1 */ >+ wlcmdint(ctlr, 10, 0); /* SET_PROMISC */ >+ //wlcmdint(ctlr, 0x8e, 0); /* SET_BAND 0 */ >+ //wlsetint(ctlr, "wsec", 1); >+ wlcmdint(ctlr, 2, 1); /* UP */ >+ ctlr->keys[0]=2Elen =3D WMinKeyLen; >+ //wlwepkey(ctlr, 0); >+} >+ >+/* >+ * Plan 9 driver interface >+ */ >+ >+static long >+etherbcmifstat(Ether* edev, void* a, long n, ulong offset) >+{ >+ Ctlr *ctlr; >+ char *p; >+ int l; >+ static char *cryptoname[4] =3D { >+ [0] "off", >+ [Wep] "wep", >+ [Wpa] "wpa", >+ [Wpa2] "wpa2", >+ }; >+ /* these strings are known by aux/wpa */ >+ static char* connectstate[] =3D { >+ [Disconnected] =3D "unassociated", >+ [Connecting] =3D "connecting", >+ [Connected] =3D "associated", >+ }; >+ >+ ctlr =3D edev->ctlr; >+ if(ctlr =3D=3D nil) >+ return 0; >+ p =3D malloc(READSTR); >+ l =3D 0; >+ >+ l +=3D snprint(p+l, READSTR-l, "channel: %d\n", ctlr->chanid); >+ l +=3D snprint(p+l, READSTR-l, "essid: %s\n", ctlr->essid); >+ l +=3D snprint(p+l, READSTR-l, "crypt: %s\n", cryptoname[ctlr->cryptoty= pe]); >+ l +=3D snprint(p+l, READSTR-l, "oq: %d\n", qlen(edev->oq)); >+ l +=3D snprint(p+l, READSTR-l, "txwin: %d\n", ctlr->txwindow); >+ l +=3D snprint(p+l, READSTR-l, "txseq: %d\n", ctlr->txseq); >+ l +=3D snprint(p+l, READSTR-l, "status: %s\n", connectstate[ctlr->statu= s]); >+ USED(l); >+ n =3D readstr(offset, a, n, p); >+ free(p); >+ return n; >+} >+ >+static void >+etherbcmtransmit(Ether *edev) >+{ >+ Ctlr *ctlr; >+ >+ ctlr =3D edev->ctlr; >+ if(ctlr =3D=3D nil) >+ return; >+ txstart(edev); >+} >+ >+static int >+parsehex(char *buf, int buflen, char *a) >+{ >+ int i, k, n; >+ >+ k =3D 0; >+ for(i =3D 0;k < buflen && *a; i++){ >+ if(*a >=3D '0' && *a <=3D '9') >+ n =3D *a++ - '0'; >+ else if(*a >=3D 'a' && *a <=3D 'f') >+ n =3D *a++ - 'a' + 10; >+ else if(*a >=3D 'A' && *a <=3D 'F') >+ n =3D *a++ - 'A' + 10; >+ else >+ break; >+ >+ if(i & 1){ >+ buf[k] |=3D n; >+ k++; >+ } >+ else >+ buf[k] =3D n<<4; >+ } >+ if(i & 1) >+ return -1; >+ return k; >+} >+ >+static int >+wepparsekey(WKey* key, char* a)=20 >+{ >+ int i, k, len, n; >+ char buf[WMaxKeyLen]; >+ >+ len =3D strlen(a); >+ if(len =3D=3D WMinKeyLen || len =3D=3D WMaxKeyLen){ >+ memset(key->dat, 0, sizeof(key->dat)); >+ memmove(key->dat, a, len); >+ key->len =3D len; >+ >+ return 0; >+ } >+ else if(len =3D=3D WMinKeyLen*2 || len =3D=3D WMaxKeyLen*2){ >+ k =3D 0; >+ for(i =3D 0; i < len; i++){ >+ if(*a >=3D '0' && *a <=3D '9') >+ n =3D *a++ - '0'; >+ else if(*a >=3D 'a' && *a <=3D 'f') >+ n =3D *a++ - 'a' + 10; >+ else if(*a >=3D 'A' && *a <=3D 'F') >+ n =3D *a++ - 'A' + 10; >+ else >+ return -1; >+=09 >+ if(i & 1){ >+ buf[k] |=3D n; >+ k++; >+ } >+ else >+ buf[k] =3D n<<4; >+ } >+ >+ memset(key->dat, 0, sizeof(key->dat)); >+ memmove(key->dat, buf, k); >+ key->len =3D k; >+ >+ return 0; >+ } >+ >+ return -1; >+} >+ >+static int >+wpaparsekey(WKey *key, uvlong *ivp, char *a) >+{ >+ int len; >+ char *e; >+ >+ if(cistrncmp(a, "tkip:", 5) =3D=3D 0 || cistrncmp(a, "ccmp:", 5) =3D=3D= 0) >+ a +=3D 5; >+ else >+ return 1; >+ len =3D parsehex(key->dat, sizeof(key->dat), a); >+ if(len <=3D 0) >+ return 1; >+ key->len =3D len; >+ a +=3D 2*len; >+ if(*a++ !=3D '@') >+ return 1; >+ *ivp =3D strtoull(a, &e, 16); >+ if(e =3D=3D a) >+ return -1; >+ return 0; >+} >+ >+static void >+setauth(Ctlr *ctlr, Cmdbuf *cb, char *a) >+{ >+ uchar wpaie[32]; >+ int i; >+ >+ i =3D parsehex((char*)wpaie, sizeof wpaie, a); >+ if(i < 2 || i !=3D wpaie[1] + 2) >+ cmderror(cb, "bad wpa ie syntax"); >+ if(wpaie[0] =3D=3D 0xdd) >+ ctlr->cryptotype =3D Wpa; >+ else if(wpaie[0] =3D=3D 0x30) >+ ctlr->cryptotype =3D Wpa2; >+ else >+ cmderror(cb, "bad wpa ie"); >+ wlsetvar(ctlr, "wpaie", wpaie, i); >+ if(ctlr->cryptotype =3D=3D Wpa){ >+ wlsetint(ctlr, "wpa_auth", 4|2); /* auth_psk | auth_unspecified */ >+ wlsetint(ctlr, "auth", 0); >+ wlsetint(ctlr, "wsec", 2); /* tkip */ >+ wlsetint(ctlr, "wpa_auth", 4); /* auth_psk */ >+ }else{ >+ wlsetint(ctlr, "wpa_auth", 0x80|0x40); /* auth_psk | auth_unspecified = */ >+ wlsetint(ctlr, "auth", 0); >+ wlsetint(ctlr, "wsec", 4); /* aes */ >+ wlsetint(ctlr, "wpa_auth", 0x80); /* auth_psk */ >+ } >+} >+ >+static int >+setcrypt(Ctlr *ctlr, Cmdbuf*, char *a) >+{ >+ if(cistrcmp(a, "wep") =3D=3D 0 || cistrcmp(a, "on") =3D=3D 0) >+ ctlr->cryptotype =3D Wep; >+ else if(cistrcmp(a, "off") =3D=3D 0 || cistrcmp(a, "none") =3D=3D 0) >+ ctlr->cryptotype =3D 0; >+ else >+ return 0; >+ wlsetint(ctlr, "auth", ctlr->cryptotype); >+ return 1; >+} >+ >+static long >+etherbcmctl(Ether* edev, void* buf, long n) >+{ >+ Ctlr *ctlr; >+ Cmdbuf *cb; >+ Cmdtab *ct; >+ uchar ea[Eaddrlen]; >+ uvlong iv; >+ int i; >+ >+ if((ctlr =3D edev->ctlr) =3D=3D nil) >+ error(Enonexist); >+ USED(ctlr); >+ >+ cb =3D parsecmd(buf, n); >+ if(waserror()){ >+ free(cb); >+ nexterror(); >+ } >+ ct =3D lookupcmd(cb, cmds, nelem(cmds)); >+ switch(ct->index){ >+ case CMauth: >+ setauth(ctlr, cb, cb->f[1]); >+ if(ctlr->essid[0]) >+ wljoin(ctlr, ctlr->essid, ctlr->chanid); >+ break; >+ case CMchannel: >+ if((i =3D atoi(cb->f[1])) < 0 || i > 16) >+ cmderror(cb, "bad channel number"); >+ //wlcmdint(ctlr, 30, i); /* SET_CHANNEL */ >+ ctlr->chanid =3D i; >+ break; >+ case CMcrypt: >+ if(setcrypt(ctlr, cb, cb->f[1])){ >+ if(ctlr->essid[0]) >+ wljoin(ctlr, ctlr->essid, ctlr->chanid); >+ }else >+ cmderror(cb, "bad crypt type"); >+ break; >+ case CMessid: >+ if(cistrcmp(cb->f[1], "default") =3D=3D 0) >+ memset(ctlr->essid, 0, sizeof(ctlr->essid)); >+ else{ >+ strncpy(ctlr->essid, cb->f[1], sizeof(ctlr->essid) - 1); >+ ctlr->essid[sizeof(ctlr->essid) - 1] =3D '\0'; >+ } >+ if(!waserror()){ >+ wljoin(ctlr, ctlr->essid, ctlr->chanid); >+ poperror(); >+ } >+ break; >+ case CMjoin: /* join essid channel wep|on|off|wpakey */ >+ if(strcmp(cb->f[1], "") !=3D 0){ /* empty string for no change */ >+ if(cistrcmp(cb->f[1], "default") !=3D 0){ >+ strncpy(ctlr->essid, cb->f[1], sizeof(ctlr->essid)-1); >+ ctlr->essid[sizeof(ctlr->essid)-1] =3D 0; >+ }else >+ memset(ctlr->essid, 0, sizeof(ctlr->essid)); >+ }else if(ctlr->essid[0] =3D=3D 0) >+ cmderror(cb, "essid not set"); >+ if((i =3D atoi(cb->f[2])) >=3D 0 && i <=3D 16) >+ ctlr->chanid =3D i; >+ else >+ cmderror(cb, "bad channel number"); >+ if(!setcrypt(ctlr, cb, cb->f[3])) >+ setauth(ctlr, cb, cb->f[3]); >+ if(ctlr->essid[0]) >+ wljoin(ctlr, ctlr->essid, ctlr->chanid); >+ break; >+ case CMkey1: >+ case CMkey2: >+ case CMkey3: >+ case CMkey4: >+ i =3D ct->index - CMkey1; >+ if(wepparsekey(&ctlr->keys[i], cb->f[1])) >+ cmderror(cb, "bad WEP key syntax"); >+ wlsetint(ctlr, "wsec", 1); /* wep enabled */ >+ wlwepkey(ctlr, i); >+ break; >+ case CMrxkey: >+ case CMrxkey0: >+ case CMrxkey1: >+ case CMrxkey2: >+ case CMrxkey3: >+ case CMtxkey: >+ if(parseether(ea, cb->f[1]) < 0) >+ cmderror(cb, "bad ether addr"); >+ if(wpaparsekey(&ctlr->keys[0], &iv, cb->f[2])) >+ cmderror(cb, "bad wpa key"); >+ wlwpakey(ctlr, ct->index, iv, ea); >+ break; >+ case CMdebug: >+ iodebug =3D atoi(cb->f[1]); >+ break; >+ } >+ poperror(); >+ free(cb); >+ return n; >+} >+ >+static void >+etherbcmscan(void *a, uint secs) >+{ >+ Ether* edev; >+ Ctlr* ctlr; >+ >+ edev =3D a; >+ ctlr =3D edev->ctlr; >+ ctlr->scansecs =3D secs; >+} >+ >+static void >+etherbcmattach(Ether* edev) >+{ >+ Ctlr *ctlr; >+ >+ ctlr =3D edev->ctlr; >+ qlock(&ctlr->alock); >+ if(waserror()){ >+ //print("ether4330: attach failed: %s\n", up->errstr); >+ qunlock(&ctlr->alock); >+ nexterror(); >+ } >+ if(ctlr->edev =3D=3D nil){ >+ if(ctlr->chipid =3D=3D 0){ >+ sdioinit(); >+ sbinit(ctlr); >+ } >+ fwload(ctlr); >+ sbenable(ctlr); >+ kproc("wifireader", rproc, edev); >+ kproc("wifitimer", lproc, edev); >+ if(ctlr->regufile) >+ reguload(ctlr, ctlr->regufile); >+ wlinit(edev, ctlr); >+ ctlr->edev =3D edev; >+ } >+ qunlock(&ctlr->alock); >+ poperror(); >+} >+ >+static void >+etherbcmshutdown(Ether*) >+{ >+ sdioreset(); >+} >+ >+ >+static int >+etherbcmpnp(Ether* edev) >+{ >+ static Ctlr *ctlr; >+ >+ if(ctlr !=3D nil) >+ return -1; >+ >+ ctlr =3D malloc(sizeof(Ctlr)); >+ ctlr->chanid =3D Wifichan; >+ edev->ctlr =3D ctlr; >+ edev->attach =3D etherbcmattach; >+ edev->transmit =3D etherbcmtransmit; >+ edev->ifstat =3D etherbcmifstat; >+ edev->ctl =3D etherbcmctl; >+ edev->scanbs =3D etherbcmscan; >+ edev->shutdown =3D etherbcmshutdown; >+ edev->arg =3D edev; >+ >+ return 0; >+} >+ >+void >+ether4330link(void) >+{ >+ addethercard("4330", etherbcmpnp); >+} >--- a/sys/src/9/bcm64/pi4 Sun Oct 22 09:21:23 2023 >+++ b/sys/src/9/bcm64/pi4 Sun Oct 22 10:53:02 2023 >@@ -32,6 +32,7 @@ > archbcm4 pci > usbxhcipci pci usbxhci archbcm4=20 > ethergenet ethermii >+ ether4330 emmc > ethermedium > loopbackmedium > netdevmedium >--- a/sys/src/9/port/sd=2Eh Sun Oct 22 09:21:23 2023 >+++ b/sys/src/9/port/sd=2Eh Sun Oct 22 10:53:02 2023 >@@ -164,6 +164,31 @@ > char *name; > }; >=20 >+/* Commands */ >+extern SDiocmd GO_IDLE_STATE; >+extern SDiocmd SEND_OP_COND; >+extern SDiocmd ALL_SEND_CID; >+extern SDiocmd SET_RELATIVE_ADDR; >+extern SDiocmd SEND_RELATIVE_ADDR; >+extern SDiocmd SWITCH; >+extern SDiocmd SWITCH_FUNC; >+extern SDiocmd SELECT_CARD; >+extern SDiocmd SEND_EXT_CSD; >+extern SDiocmd SD_SEND_IF_COND; >+extern SDiocmd SEND_CSD; >+extern SDiocmd STOP_TRANSMISSION; >+extern SDiocmd SEND_STATUS; >+extern SDiocmd SET_BLOCKLEN; >+extern SDiocmd READ_SINGLE_BLOCK; >+extern SDiocmd READ_MULTIPLE_BLOCK; >+extern SDiocmd WRITE_SINGLE_BLOCK; >+extern SDiocmd WRITE_MULTIPLE_BLOCK; >+ >+/* prefix for following app-specific commands */ >+extern SDiocmd APP_CMD; >+extern SDiocmd SD_SET_BUS_WIDTH; >+extern SDiocmd SD_SEND_OP_COND; >+ > struct SDio { > char *name; > int (*init)(SDio*); > > let me rephrase: is this known to actually work, and which hardware does i= t actually work with=2E asking for a fqa=2E sl