xref: /plan9-contrib/sys/src/9/bcm/ether4330.c (revision 5c47fe09a0cc86dfb02c0ea4a2b6aec7eda2361f)
1 /*
2  * Broadcom bcm4330 wifi (sdio interface)
3  */
4 
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "io.h"
11 #include "../port/error.h"
12 #include "../port/netif.h"
13 #include "../port/sd.h"
14 
15 extern int sdiocardintr(int);
16 
17 #include "etherif.h"
18 #define CACHELINESZ 64	/* temp */
19 
20 enum{
21 	SDIODEBUG = 0,
22 	SBDEBUG = 0,
23 	EVENTDEBUG = 0,
24 	VARDEBUG = 0,
25 	FWDEBUG  = 0,
26 
27 	Corescansz = 512,
28 	Uploadsz = 2048,
29 
30 	Wifichan = 0,		/* default channel */
31 	Firmwarecmp	= 1,
32 
33 	ARMcm3		= 0x82A,
34 	ARM7tdmi	= 0x825,
35 	ARMcr4		= 0x83E,
36 
37 	Fn0	= 0,
38 	Fn1 	= 1,
39 	Fn2	= 2,
40 	Fbr1	= 0x100,
41 	Fbr2	= 0x200,
42 
43 	/* CCCR */
44 	Ioenable	= 0x02,
45 	Ioready		= 0x03,
46 	Intenable	= 0x04,
47 	Intpend		= 0x05,
48 	Ioabort		= 0x06,
49 	Busifc		= 0x07,
50 	Capability	= 0x08,
51 	Blksize		= 0x10,
52 	Highspeed	= 0x13,
53 
54 	/* SDIOCommands */
55 	GO_IDLE_STATE		= 0,
56 	SEND_RELATIVE_ADDR	= 3,
57 	IO_SEND_OP_COND		= 5,
58 	SELECT_CARD		= 7,
59 	VOLTAGE_SWITCH 		= 11,
60 	IO_RW_DIRECT 		= 52,
61 	IO_RW_EXTENDED 		= 53,
62 
63 	/* SELECT_CARD args */
64 	Rcashift	= 16,
65 
66 	/* SEND_OP_COND args */
67 	Hcs	= 1<<30,	/* host supports SDHC & SDXC */
68 	V3_3	= 3<<20,	/* 3.2-3.4 volts */
69 	V2_8	= 3<<15,	/* 2.7-2.9 volts */
70 	V2_0	= 1<<8,		/* 2.0-2.1 volts */
71 	S18R	= 1<<24,	/* switch to 1.8V request */
72 
73 	/* Sonics Silicon Backplane (access to cores on chip) */
74 	Sbwsize	= 0x8000,
75 	Sb32bit	= 0x8000,
76 	Sbaddr	= 0x1000a,
77 		Enumbase	= 	0x18000000,
78 	Framectl= 0x1000d,
79 		Rfhalt		=	0x01,
80 		Wfhalt		=	0x02,
81 	Clkcsr	= 0x1000e,
82 		ForceALP	=	0x01,	/* active low-power clock */
83 		ForceHT		= 	0x02,	/* high throughput clock */
84 		ForceILP	=	0x04,	/* idle low-power clock */
85 		ReqALP		=	0x08,
86 		ReqHT		=	0x10,
87 		Nohwreq		=	0x20,
88 		ALPavail	=	0x40,
89 		HTavail		=	0x80,
90 	Pullups	= 0x1000f,
91 	Wfrmcnt	= 0x10019,
92 	Rfrmcnt	= 0x1001b,
93 
94 	/* core control regs */
95 	Ioctrl		= 0x408,
96 	Resetctrl	= 0x800,
97 
98 	/* socram regs */
99 	Coreinfo	= 0x00,
100 	Bankidx		= 0x10,
101 	Bankinfo	= 0x40,
102 	Bankpda		= 0x44,
103 
104 	/* armcr4 regs */
105 	Cr4Cap		= 0x04,
106 	Cr4Bankidx	= 0x40,
107 	Cr4Bankinfo	= 0x44,
108 	Cr4Cpuhalt	= 0x20,
109 
110 	/* chipcommon regs */
111 	Gpiopullup	= 0x58,
112 	Gpiopulldown	= 0x5c,
113 	Chipctladdr	= 0x650,
114 	Chipctldata	= 0x654,
115 
116 	/* sdio core regs */
117 	Intstatus	= 0x20,
118 		Fcstate		= 1<<4,
119 		Fcchange	= 1<<5,
120 		FrameInt	= 1<<6,
121 		MailboxInt	= 1<<7,
122 	Intmask		= 0x24,
123 	Sbmbox		= 0x40,
124 	Sbmboxdata	= 0x48,
125 	Hostmboxdata= 0x4c,
126 		Fwready		= 0x80,
127 
128 	/* wifi control commands */
129 	GetVar	= 262,
130 	SetVar	= 263,
131 
132 	/* status */
133 	Disconnected=	0,
134 	Connecting,
135 	Connected,
136 };
137 
138 typedef struct Ctlr Ctlr;
139 
140 enum{
141 	Wpa		= 1,
142 	Wep		= 2,
143 	Wpa2		= 3,
144 	WNameLen	= 32,
145 	WNKeys		= 4,
146 	WKeyLen		= 32,
147 	WMinKeyLen	= 5,
148 	WMaxKeyLen	= 13,
149 };
150 
151 typedef struct WKey WKey;
152 struct WKey
153 {
154 	ushort	len;
155 	char	dat[WKeyLen];
156 };
157 
158 struct Ctlr {
159 	Ether*	edev;
160 	QLock	cmdlock;
161 	QLock	pktlock;
162 	QLock	tlock;
163 	QLock	alock;
164 	Lock	txwinlock;
165 	Rendez	cmdr;
166 	Rendez	joinr;
167 	int	joinstatus;
168 	int	cryptotype;
169 	int	chanid;
170 	char	essid[WNameLen + 1];
171 	WKey	keys[WNKeys];
172 	Block	*rsp;
173 	Block	*scanb;
174 	int	scansecs;
175 	int	status;
176 	int	chipid;
177 	int	chiprev;
178 	int	armcore;
179 	char	*regufile;
180 	union {
181 		u32int i;
182 		uchar c[4];
183 	} resetvec;
184 	ulong	chipcommon;
185 	ulong	armctl;
186 	ulong	armregs;
187 	ulong	d11ctl;
188 	ulong	socramregs;
189 	ulong	socramctl;
190 	ulong	sdregs;
191 	int	sdiorev;
192 	int	socramrev;
193 	ulong	socramsize;
194 	ulong	rambase;
195 	short	reqid;
196 	uchar	fcmask;
197 	uchar	txwindow;
198 	uchar	txseq;
199 	uchar	rxseq;
200 };
201 
202 enum{
203 	CMauth,
204 	CMchannel,
205 	CMcrypt,
206 	CMessid,
207 	CMkey1,
208 	CMkey2,
209 	CMkey3,
210 	CMkey4,
211 	CMrxkey,
212 	CMrxkey0,
213 	CMrxkey1,
214 	CMrxkey2,
215 	CMrxkey3,
216 	CMtxkey,
217 	CMdebug,
218 	CMjoin,
219 };
220 
221 static Cmdtab cmds[] = {
222 	{CMauth,	"auth", 2},
223 	{CMchannel,	"channel", 2},
224 	{CMcrypt,	"crypt", 2},
225 	{CMessid,	"essid", 2},
226 	{CMkey1,	"key1",	2},
227 	{CMkey2,	"key1",	2},
228 	{CMkey3,	"key1",	2},
229 	{CMkey4,	"key1",	2},
230 	{CMrxkey,	"rxkey", 3},
231 	{CMrxkey0,	"rxkey0", 3},
232 	{CMrxkey1,	"rxkey1", 3},
233 	{CMrxkey2,	"rxkey2", 3},
234 	{CMrxkey3,	"rxkey3", 3},
235 	{CMtxkey,	"txkey", 3},
236 	{CMdebug,	"debug", 2},
237 	{CMjoin,	"join", 5},
238 };
239 
240 typedef struct Sdpcm Sdpcm;
241 typedef struct Cmd Cmd;
242 struct Sdpcm {
243 	uchar	len[2];
244 	uchar	lenck[2];
245 	uchar	seq;
246 	uchar	chanflg;
247 	uchar	nextlen;
248 	uchar	doffset;
249 	uchar	fcmask;
250 	uchar	window;
251 	uchar	version;
252 	uchar	pad;
253 };
254 
255 struct Cmd {
256 	uchar	cmd[4];
257 	uchar	len[4];
258 	uchar	flags[2];
259 	uchar	id[2];
260 	uchar	status[4];
261 };
262 
263 static char config40181[] = "bcmdhd.cal.40181";
264 static char config40183[] = "bcmdhd.cal.40183.26MHz";
265 
266 struct {
267 	int chipid;
268 	int chiprev;
269 	char *fwfile;
270 	char *cfgfile;
271 	char *regufile;
272 } firmware[] = {
273 	{ 0x4330, 3,	"fw_bcm40183b1.bin", config40183, 0 },
274 	{ 0x4330, 4,	"fw_bcm40183b2.bin", config40183, 0 },
275 	{ 43362, 0,	"fw_bcm40181a0.bin", config40181, 0 },
276 	{ 43362, 1,	"fw_bcm40181a2.bin", config40181, 0 },
277 	{ 43430, 1,	"brcmfmac43430-sdio.bin", "brcmfmac43430-sdio.txt", 0 },
278 	{ 43430, 2,	"brcmfmac43436-sdio.bin", "brcmfmac43436-sdio.txt",  "brcmfmac43436-sdio.clm_blob" },
279 	{ 0x4345, 6, "brcmfmac43455-sdio.bin", "brcmfmac43455-sdio.txt", "brcmfmac43455-sdio.clm_blob" },
280 };
281 
282 static QLock sdiolock;
283 static int iodebug;
284 
285 static void etherbcmintr(void *);
286 static void bcmevent(Ctlr*, uchar*, int);
287 static void wlscanresult(Ether*, uchar*, int);
288 static void wlsetvar(Ctlr*, char*, void*, int);
289 
290 static uchar*
put2(uchar * p,short v)291 put2(uchar *p, short v)
292 {
293 	p[0] = v;
294 	p[1] = v >> 8;
295 	return p + 2;
296 }
297 
298 static uchar*
put4(uchar * p,long v)299 put4(uchar *p, long v)
300 {
301 	p[0] = v;
302 	p[1] = v >> 8;
303 	p[2] = v >> 16;
304 	p[3] = v >> 24;
305 	return p + 4;
306 }
307 
308 static ushort
get2(uchar * p)309 get2(uchar *p)
310 {
311 	return p[0] | p[1]<<8;
312 }
313 
314 static ulong
get4(uchar * p)315 get4(uchar *p)
316 {
317 	return p[0] | p[1]<<8 | p[2]<<16 | p[3]<<24;
318 }
319 
320 static void
dump(char * s,void * a,int n)321 dump(char *s, void *a, int n)
322 {
323 	int i;
324 	uchar *p;
325 
326 	p = a;
327 	print("%s:", s);
328 	for(i = 0; i < n; i++)
329 		print("%c%2.2x", i&15? ' ' : '\n', *p++);
330 	print("\n");
331 }
332 
333 /*
334  * SDIO communication with dongle
335  */
336 static ulong
sdiocmd_locked(int cmd,ulong arg)337 sdiocmd_locked(int cmd, ulong arg)
338 {
339 	u32int resp[4];
340 
341 	sdio.cmd(cmd, arg, resp);
342 	return resp[0];
343 }
344 
345 static ulong
sdiocmd(int cmd,ulong arg)346 sdiocmd(int cmd, ulong arg)
347 {
348 	ulong r;
349 
350 	qlock(&sdiolock);
351 	if(waserror()){
352 		if(SDIODEBUG) print("sdiocmd error: cmd %d arg %lux\n", cmd, arg);
353 		qunlock(&sdiolock);
354 		nexterror();
355 	}
356 	r = sdiocmd_locked(cmd, arg);
357 	qunlock(&sdiolock);
358 	poperror();
359 	return r;
360 
361 }
362 
363 static ulong
trysdiocmd(int cmd,ulong arg)364 trysdiocmd(int cmd, ulong arg)
365 {
366 	ulong r;
367 
368 	if(waserror())
369 		return 0;
370 	r = sdiocmd(cmd, arg);
371 	poperror();
372 	return r;
373 }
374 
375 static int
sdiord(int fn,int addr)376 sdiord(int fn, int addr)
377 {
378 	int r;
379 
380 	r = sdiocmd(IO_RW_DIRECT, (0<<31)|((fn&7)<<28)|((addr&0x1FFFF)<<9));
381 	if(r & 0xCF00){
382 		print("ether4330: sdiord(%x, %x) fail: %2.2ux %2.2ux\n", fn, addr, (r>>8)&0xFF, r&0xFF);
383 		error(Eio);
384 	}
385 	return r & 0xFF;
386 }
387 
388 static void
sdiowr(int fn,int addr,int data)389 sdiowr(int fn, int addr, int data)
390 {
391 	int r;
392 	int retry;
393 
394 	r = 0;
395 	for(retry = 0; retry < 10; retry++){
396 		r = sdiocmd(IO_RW_DIRECT, (1<<31)|((fn&7)<<28)|((addr&0x1FFFF)<<9)|(data&0xFF));
397 		if((r & 0xCF00) == 0)
398 			return;
399 	}
400 	print("ether4330: sdiowr(%x, %x, %x) fail: %2.2ux %2.2ux\n", fn, addr, data, (r>>8)&0xFF, r&0xFF);
401 	error(Eio);
402 }
403 
404 static void
sdiorwext(int fn,int write,void * a,int len,int addr,int incr)405 sdiorwext(int fn, int write, void *a, int len, int addr, int incr)
406 {
407 	int bsize, blk, bcount, m;
408 
409 	bsize = fn == Fn2? 512 : 64;
410 	while(len > 0){
411 		if(len >= 511*bsize){
412 			blk = 1;
413 			bcount = 511;
414 			m = bcount*bsize;
415 		}else if(len > bsize){
416 			blk = 1;
417 			bcount = len/bsize;
418 			m = bcount*bsize;
419 		}else{
420 			blk = 0;
421 			bcount = len;
422 			m = bcount;
423 		}
424 		qlock(&sdiolock);
425 		if(waserror()){
426 			print("ether4330: sdiorwext fail: %s\n", up->errstr);
427 			qunlock(&sdiolock);
428 			nexterror();
429 		}
430 		if(blk)
431 			sdio.iosetup(write, a, bsize, bcount);
432 		else
433 			sdio.iosetup(write, a, bcount, 1);
434 		sdiocmd_locked(IO_RW_EXTENDED,
435 			write<<31 | (fn&7)<<28 | blk<<27 | incr<<26 | (addr&0x1FFFF)<<9 | (bcount&0x1FF));
436 		sdio.io(write, a, m);
437 		qunlock(&sdiolock);
438 		poperror();
439 		len -= m;
440 		a = (char*)a + m;
441 		if(incr)
442 			addr += m;
443 	}
444 }
445 
446 static void
sdioset(int fn,int addr,int bits)447 sdioset(int fn, int addr, int bits)
448 {
449 	sdiowr(fn, addr, sdiord(fn, addr) | bits);
450 }
451 
452 static void
sdioinit(void)453 sdioinit(void)
454 {
455 	ulong ocr, rca;
456 	int i;
457 
458 	/* disconnect emmc from SD card (connect sdhost instead) */
459 	for(i = 48; i <= 53; i++)
460 		gpiosel(i, Alt0);
461 	/* connect emmc to wifi */
462 	for(i = 34; i <= 39; i++){
463 		gpiosel(i, Alt3);
464 		if(i == 34)
465 			gpiopulloff(i);
466 		else
467 			gpiopullup(i);
468 	}
469 	sdio.init();
470 	sdio.enable();
471 	sdiocmd(GO_IDLE_STATE, 0);
472 	ocr = trysdiocmd(IO_SEND_OP_COND, 0);
473 	i = 0;
474 	while((ocr & (1<<31)) == 0){
475 		if(++i > 5){
476 			print("ether4330: no response to sdio access: ocr = %lux\n", ocr);
477 			error(Eio);
478 		}
479 		ocr = trysdiocmd(IO_SEND_OP_COND, V3_3);
480 		tsleep(&up->sleep, return0, nil, 100);
481 	}
482 	rca = sdiocmd(SEND_RELATIVE_ADDR, 0) >> Rcashift;
483 	sdiocmd(SELECT_CARD, rca << Rcashift);
484 	sdioset(Fn0, Highspeed, 2);
485 	sdioset(Fn0, Busifc, 2);	/* bus width 4 */
486 	sdiowr(Fn0, Fbr1+Blksize, 64);
487 	sdiowr(Fn0, Fbr1+Blksize+1, 64>>8);
488 	sdiowr(Fn0, Fbr2+Blksize, 512);
489 	sdiowr(Fn0, Fbr2+Blksize+1, 512>>8);
490 	sdioset(Fn0, Ioenable, 1<<Fn1);
491 	sdiowr(Fn0, Intenable, 0);
492 	for(i = 0; !(sdiord(Fn0, Ioready) & 1<<Fn1); i++){
493 		if(i == 10){
494 			print("ether4330: can't enable SDIO function\n");
495 			error(Eio);
496 		}
497 		tsleep(&up->sleep, return0, nil, 100);
498 	}
499 }
500 
501 static void
sdioreset(void)502 sdioreset(void)
503 {
504 	sdiowr(Fn0, Ioabort, 1<<3);	/* reset */
505 }
506 
507 static void
sdioabort(int fn)508 sdioabort(int fn)
509 {
510 	sdiowr(Fn0, Ioabort, fn);
511 }
512 
513 /*
514  * Chip register and memory access via SDIO
515  */
516 
517 static void
cfgw(ulong off,int val)518 cfgw(ulong off, int val)
519 {
520 	sdiowr(Fn1, off, val);
521 }
522 
523 static int
cfgr(ulong off)524 cfgr(ulong off)
525 {
526 	return sdiord(Fn1, off);
527 }
528 
529 static ulong
cfgreadl(int fn,ulong off)530 cfgreadl(int fn, ulong off)
531 {
532 	uchar cbuf[2*CACHELINESZ];
533 	uchar *p;
534 
535 	p = (uchar*)ROUND((uintptr)cbuf, CACHELINESZ);
536 	memset(p, 0, 4);
537 	sdiorwext(fn, 0, p, 4, off|Sb32bit, 1);
538 	if(SDIODEBUG) print("cfgreadl %lux: %2.2x %2.2x %2.2x %2.2x\n", off, p[0], p[1], p[2], p[3]);
539 	return p[0] | p[1]<<8 | p[2]<<16 | p[3]<<24;
540 }
541 
542 static void
cfgwritel(int fn,ulong off,u32int data)543 cfgwritel(int fn, ulong off, u32int data)
544 {
545 	uchar cbuf[2*CACHELINESZ];
546 	uchar *p;
547 	int retry;
548 
549 	p = (uchar*)ROUND((uintptr)cbuf, CACHELINESZ);
550 	put4(p, data);
551 	if(SDIODEBUG) print("cfgwritel %lux: %2.2x %2.2x %2.2x %2.2x\n", off, p[0], p[1], p[2], p[3]);
552 	retry = 0;
553 	while(waserror()){
554 		print("ether4330: cfgwritel retry %lux %ux\n", off, data);
555 		sdioabort(fn);
556 		if(++retry == 3)
557 			nexterror();
558 	}
559 	sdiorwext(fn, 1, p, 4, off|Sb32bit, 1);
560 	poperror();
561 }
562 
563 static void
sbwindow(ulong addr)564 sbwindow(ulong addr)
565 {
566 	addr &= ~(Sbwsize-1);
567 	cfgw(Sbaddr, addr>>8);
568 	cfgw(Sbaddr+1, addr>>16);
569 	cfgw(Sbaddr+2, addr>>24);
570 }
571 
572 static void
sbrw(int fn,int write,uchar * buf,int len,ulong off)573 sbrw(int fn, int write, uchar *buf, int len, ulong off)
574 {
575 	int n;
576 	USED(fn);
577 
578 	if(waserror()){
579 		print("ether4330: sbrw err off %lux len %ud\n", off, len);
580 		nexterror();
581 	}
582 	if(write){
583 		if(len >= 4){
584 			n = len;
585 			n &= ~3;
586 			sdiorwext(Fn1, write, buf, n, off|Sb32bit, 1);
587 			off += n;
588 			buf += n;
589 			len -= n;
590 		}
591 		while(len > 0){
592 			sdiowr(Fn1, off|Sb32bit, *buf);
593 			off++;
594 			buf++;
595 			len--;
596 		}
597 	}else{
598 		if(len >= 4){
599 			n = len;
600 			n &= ~3;
601 			sdiorwext(Fn1, write, buf, n, off|Sb32bit, 1);
602 			off += n;
603 			buf += n;
604 			len -= n;
605 		}
606 		while(len > 0){
607 			*buf = sdiord(Fn1, off|Sb32bit);
608 			off++;
609 			buf++;
610 			len--;
611 		}
612 	}
613 	poperror();
614 }
615 
616 static void
sbmem(int write,uchar * buf,int len,ulong off)617 sbmem(int write, uchar *buf, int len, ulong off)
618 {
619 	ulong n;
620 
621 	n = ROUNDUP(off, Sbwsize) - off;
622 	if(n == 0)
623 		n = Sbwsize;
624 	while(len > 0){
625 		if(n > len)
626 			n = len;
627 		sbwindow(off);
628 		sbrw(Fn1, write, buf, n, off & (Sbwsize-1));
629 		off += n;
630 		buf += n;
631 		len -= n;
632 		n = Sbwsize;
633 	}
634 }
635 
636 static void
packetrw(int write,uchar * buf,int len)637 packetrw(int write, uchar *buf, int len)
638 {
639 	int n;
640 	int retry;
641 
642 	n = 2048;
643 	while(len > 0){
644 		if(n > len)
645 			n = ROUND(len, 4);
646 		retry = 0;
647 		while(waserror()){
648 			sdioabort(Fn2);
649 			if(++retry == 3)
650 				nexterror();
651 		}
652 		sdiorwext(Fn2, write, buf, n, Enumbase, 0);
653 		poperror();
654 		buf += n;
655 		len -= n;
656 	}
657 }
658 
659 /*
660  * Configuration and control of chip cores via Silicon Backplane
661  */
662 
663 static void
sbdisable(ulong regs,int pre,int ioctl)664 sbdisable(ulong regs, int pre, int ioctl)
665 {
666 	sbwindow(regs);
667 	if((cfgreadl(Fn1, regs + Resetctrl) & 1) != 0){
668 		cfgwritel(Fn1, regs + Ioctrl, 3|ioctl);
669 		cfgreadl(Fn1, regs + Ioctrl);
670 		return;
671 	}
672 	cfgwritel(Fn1, regs + Ioctrl, 3|pre);
673 	cfgreadl(Fn1, regs + Ioctrl);
674 	cfgwritel(Fn1, regs + Resetctrl, 1);
675 	microdelay(10);
676 	while((cfgreadl(Fn1, regs + Resetctrl) & 1) == 0)
677 		;
678 	cfgwritel(Fn1, regs + Ioctrl, 3|ioctl);
679 	cfgreadl(Fn1, regs + Ioctrl);
680 }
681 
682 static void
sbreset(ulong regs,int pre,int ioctl)683 sbreset(ulong regs, int pre, int ioctl)
684 {
685 	sbdisable(regs, pre, ioctl);
686 	sbwindow(regs);
687 	if(SBDEBUG) print("sbreset %#p %#lux %#lux ->", regs,
688 		cfgreadl(Fn1, regs+Ioctrl), cfgreadl(Fn1, regs+Resetctrl));
689 	while((cfgreadl(Fn1, regs + Resetctrl) & 1) != 0){
690 		cfgwritel(Fn1, regs + Resetctrl, 0);
691 		microdelay(40);
692 	}
693 	cfgwritel(Fn1, regs + Ioctrl, 1|ioctl);
694 	cfgreadl(Fn1, regs + Ioctrl);
695 	if(SBDEBUG) print("%#lux %#lux\n",
696 		cfgreadl(Fn1, regs+Ioctrl), cfgreadl(Fn1, regs+Resetctrl));
697 }
698 
699 static void
corescan(Ctlr * ctl,ulong r)700 corescan(Ctlr *ctl, ulong r)
701 {
702 	uchar *buf;
703 	int i, coreid, corerev;
704 	ulong addr;
705 
706 	buf = sdmalloc(Corescansz);
707 	if(buf == nil)
708 		error(Enomem);
709 	sbmem(0, buf, Corescansz, r);
710 	coreid = 0;
711 	corerev = 0;
712 	for(i = 0; i < Corescansz; i += 4){
713 		switch(buf[i]&0xF){
714 		case 0xF:	/* end */
715 			sdfree(buf);
716 			return;
717 		case 0x1:	/* core info */
718 			if((buf[i+4]&0xF) != 0x1)
719 				break;
720 			coreid = (buf[i+1] | buf[i+2]<<8) & 0xFFF;
721 			i += 4;
722 			corerev = buf[i+3];
723 			break;
724 		case 0x05:	/* address */
725 			addr = buf[i+1]<<8 | buf[i+2]<<16 | buf[i+3]<<24;
726 			addr &= ~0xFFF;
727 			if(SBDEBUG) print("core %x %s %#p\n", coreid, buf[i]&0xC0? "ctl" : "mem", addr);
728 			switch(coreid){
729 			case 0x800:
730 				if((buf[i] & 0xC0) == 0)
731 					ctl->chipcommon = addr;
732 				break;
733 			case ARMcm3:
734 			case ARM7tdmi:
735 			case ARMcr4:
736 				ctl->armcore = coreid;
737 				if(buf[i] & 0xC0){
738 					if(ctl->armctl == 0)
739 						ctl->armctl = addr;
740 				}else{
741 					if(ctl->armregs == 0)
742 						ctl->armregs = addr;
743 				}
744 				break;
745 			case 0x80E:
746 				if(buf[i] & 0xC0)
747 					ctl->socramctl = addr;
748 				else if(ctl->socramregs == 0)
749 					ctl->socramregs = addr;
750 				ctl->socramrev = corerev;
751 				break;
752 			case 0x829:
753 				if((buf[i] & 0xC0) == 0)
754 					ctl->sdregs = addr;
755 				ctl->sdiorev = corerev;
756 				break;
757 			case 0x812:
758 				if(buf[i] & 0xC0)
759 					ctl->d11ctl = addr;
760 				break;
761 			}
762 		}
763 	}
764 	sdfree(buf);
765 }
766 
767 static void
ramscan(Ctlr * ctl)768 ramscan(Ctlr *ctl)
769 {
770 	ulong r, n, size;
771 	int banks, i;
772 
773 	if(ctl->armcore == ARMcr4){
774 		r = ctl->armregs;
775 		sbwindow(r);
776 		n = cfgreadl(Fn1, r + Cr4Cap);
777 		if(SBDEBUG) print("cr4 banks %lux\n", n);
778 		banks = ((n>>4) & 0xF) + (n & 0xF);
779 		size = 0;
780 		for(i = 0; i < banks; i++){
781 			cfgwritel(Fn1, r + Cr4Bankidx, i);
782 			n = cfgreadl(Fn1, r + Cr4Bankinfo);
783 			if(SBDEBUG) print("bank %d reg %lux size %lud\n", i, n, 8192 * ((n & 0x3F) + 1));
784 			size += 8192 * ((n & 0x3F) + 1);
785 		}
786 		ctl->socramsize = size;
787 		ctl->rambase = 0x198000;
788 		return;
789 	}
790 	if(ctl->socramrev <= 7 || ctl->socramrev == 12){
791 		print("ether4330: SOCRAM rev %d not supported\n", ctl->socramrev);
792 		error(Eio);
793 	}
794 	sbreset(ctl->socramctl, 0, 0);
795 	r = ctl->socramregs;
796 	sbwindow(r);
797 	n = cfgreadl(Fn1, r + Coreinfo);
798 	if(SBDEBUG) print("socramrev %d coreinfo %lux\n", ctl->socramrev, n);
799 	banks = (n>>4) & 0xF;
800 	size = 0;
801 	for(i = 0; i < banks; i++){
802 		cfgwritel(Fn1, r + Bankidx, i);
803 		n = cfgreadl(Fn1, r + Bankinfo);
804 		if(SBDEBUG) print("bank %d reg %lux size %lud\n", i, n, 8192 * ((n & 0x3F) + 1));
805 		size += 8192 * ((n & 0x3F) + 1);
806 	}
807 	ctl->socramsize = size;
808 	ctl->rambase = 0;
809 	if(ctl->chipid == 43430){
810 		cfgwritel(Fn1, r + Bankidx, 3);
811 		cfgwritel(Fn1, r + Bankpda, 0);
812 	}
813 }
814 
815 static void
sbinit(Ctlr * ctl)816 sbinit(Ctlr *ctl)
817 {
818 	ulong r;
819 	int chipid;
820 	char buf[16];
821 
822 	sbwindow(Enumbase);
823 	r = cfgreadl(Fn1, Enumbase);
824 	chipid = r & 0xFFFF;
825 	sprint(buf, chipid > 43000 ? "%d" : "%#x", chipid);
826 	print("ether4330: chip %s rev %ld type %ld\n", buf, (r>>16)&0xF, (r>>28)&0xF);
827 	switch(chipid){
828 		case 0x4330:
829 		case 43362:
830 		case 43430:
831 		case 0x4345:
832 			ctl->chipid = chipid;
833 			ctl->chiprev = (r>>16)&0xF;
834 			break;
835 		default:
836 			print("ether4330: chipid %#x (%d) not supported\n", chipid, chipid);
837 			error(Eio);
838 	}
839 	r = cfgreadl(Fn1, Enumbase + 63*4);
840 	corescan(ctl, r);
841 	if(ctl->armctl == 0 || ctl->d11ctl == 0 ||
842 	   (ctl->armcore == ARMcm3 && (ctl->socramctl == 0 || ctl->socramregs == 0)))
843 		error("corescan didn't find essential cores\n");
844 	if(ctl->armcore == ARMcr4)
845 		sbreset(ctl->armctl, Cr4Cpuhalt, Cr4Cpuhalt);
846 	else
847 		sbdisable(ctl->armctl, 0, 0);
848 	sbreset(ctl->d11ctl, 8|4, 4);
849 	ramscan(ctl);
850 	if(SBDEBUG) print("ARM %#p D11 %#p SOCRAM %#p,%#p %lud bytes @ %#p\n",
851 		ctl->armctl, ctl->d11ctl, ctl->socramctl, ctl->socramregs, ctl->socramsize, ctl->rambase);
852 	cfgw(Clkcsr, 0);
853 	microdelay(10);
854 	if(SBDEBUG) print("chipclk: %x\n", cfgr(Clkcsr));
855 	cfgw(Clkcsr, Nohwreq | ReqALP);
856 	while((cfgr(Clkcsr) & (HTavail|ALPavail)) == 0)
857 		microdelay(10);
858 	cfgw(Clkcsr, Nohwreq | ForceALP);
859 	microdelay(65);
860 	if(SBDEBUG) print("chipclk: %x\n", cfgr(Clkcsr));
861 	cfgw(Pullups, 0);
862 	sbwindow(ctl->chipcommon);
863 	cfgwritel(Fn1, ctl->chipcommon + Gpiopullup, 0);
864 	cfgwritel(Fn1, ctl->chipcommon + Gpiopulldown, 0);
865 	if(ctl->chipid != 0x4330 && ctl->chipid != 43362)
866 		return;
867 	cfgwritel(Fn1, ctl->chipcommon + Chipctladdr, 1);
868 	if(cfgreadl(Fn1, ctl->chipcommon + Chipctladdr) != 1)
869 		print("ether4330: can't set Chipctladdr\n");
870 	else{
871 		r = cfgreadl(Fn1, ctl->chipcommon + Chipctldata);
872 		if(SBDEBUG) print("chipcommon PMU (%lux) %lux", cfgreadl(Fn1, ctl->chipcommon + Chipctladdr), r);
873 		/* set SDIO drive strength >= 6mA */
874 		r &= ~0x3800;
875 		if(ctl->chipid == 0x4330)
876 			r |= 3<<11;
877 		else
878 			r |= 7<<11;
879 		cfgwritel(Fn1, ctl->chipcommon + Chipctldata, r);
880 		if(SBDEBUG) print("-> %lux (= %lux)\n", r, cfgreadl(Fn1, ctl->chipcommon + Chipctldata));
881 	}
882 }
883 
884 static void
sbenable(Ctlr * ctl)885 sbenable(Ctlr *ctl)
886 {
887 	int i;
888 
889 	if(SBDEBUG) print("enabling HT clock...");
890 	cfgw(Clkcsr, 0);
891 	delay(1);
892 	cfgw(Clkcsr, ReqHT);
893 	for(i = 0; (cfgr(Clkcsr) & HTavail) == 0; i++){
894 		if(i == 50){
895 			print("ether4330: can't enable HT clock: csr %x\n", cfgr(Clkcsr));
896 			error(Eio);
897 		}
898 		tsleep(&up->sleep, return0, nil, 100);
899 	}
900 	cfgw(Clkcsr, cfgr(Clkcsr) | ForceHT);
901 	delay(10);
902 	if(SBDEBUG) print("chipclk: %x\n", cfgr(Clkcsr));
903 	sbwindow(ctl->sdregs);
904 	cfgwritel(Fn1, ctl->sdregs + Sbmboxdata, 4 << 16);	/* protocol version */
905 	cfgwritel(Fn1, ctl->sdregs + Intmask, FrameInt | MailboxInt | Fcchange);
906 	sdioset(Fn0, Ioenable, 1<<Fn2);
907 	for(i = 0; !(sdiord(Fn0, Ioready) & 1<<Fn2); i++){
908 		if(i == 10){
909 			print("ether4330: can't enable SDIO function 2 - ioready %x\n", sdiord(Fn0, Ioready));
910 			error(Eio);
911 		}
912 		tsleep(&up->sleep, return0, nil, 100);
913 	}
914 	sdiowr(Fn0, Intenable, (1<<Fn1) | (1<<Fn2) | 1);
915 }
916 
917 
918 /*
919  * Firmware and config file uploading
920  */
921 
922 /*
923  * Condense config file contents (in buffer buf with length n)
924  * to 'var=value\0' list for firmware:
925  *	- remove comments (starting with '#') and blank lines
926  *	- remove carriage returns
927  *	- convert newlines to nulls
928  *	- mark end with two nulls
929  *	- pad with nulls to multiple of 4 bytes total length
930  */
931 static int
condense(uchar * buf,int n)932 condense(uchar *buf, int n)
933 {
934 	uchar *p, *ep, *lp, *op;
935 	int c, skipping;
936 
937 	skipping = 0;	/* true if in a comment */
938 	ep = buf + n;	/* end of input */
939 	op = buf;	/* end of output */
940 	lp = buf;	/* start of current output line */
941 	for(p = buf; p < ep; p++){
942 		switch(c = *p){
943 		case '#':
944 			skipping = 1;
945 			break;
946 		case '\0':
947 		case '\n':
948 			skipping = 0;
949 			if(op != lp){
950 				*op++ = '\0';
951 				lp = op;
952 			}
953 			break;
954 		case '\r':
955 			break;
956 		default:
957 			if(!skipping)
958 				*op++ = c;
959 			break;
960 		}
961 	}
962 	if(!skipping && op != lp)
963 		*op++ = '\0';
964 	*op++ = '\0';
965 	for(n = op - buf; n & 03; n++)
966 		*op++ = '\0';
967 	return n;
968 }
969 
970 /*
971  * Try to find firmware file in /boot or in /sys/lib/firmware.
972  * Throw an error if not found.
973  */
974 static Chan*
findfirmware(char * file)975 findfirmware(char *file)
976 {
977 	char nbuf[64];
978 	Chan *c;
979 
980 	if(!waserror()){
981 		snprint(nbuf, sizeof nbuf, "/boot/%s", file);
982 		c = namec(nbuf, Aopen, OREAD, 0);
983 		poperror();
984 	}else if(!waserror()){
985 		snprint(nbuf, sizeof nbuf, "/sys/lib/firmware/%s", file);
986 		c = namec(nbuf, Aopen, OREAD, 0);
987 		poperror();
988 	}else{
989 		c = nil;
990 		snprint(up->genbuf, sizeof up->genbuf, "can't find %s in /boot or /sys/lib/firmware", file);
991 		error(up->genbuf);
992 	}
993 	return c;
994 }
995 
996 static int
upload(Ctlr * ctl,char * file,int isconfig)997 upload(Ctlr *ctl, char *file, int isconfig)
998 {
999 	Chan *c;
1000 	uchar *buf;
1001 	uchar *cbuf;
1002 	int off, n;
1003 
1004 	buf = cbuf = nil;
1005 	c = findfirmware(file);
1006 	if(waserror()){
1007 		cclose(c);
1008 		sdfree(buf);
1009 		sdfree(cbuf);
1010 		nexterror();
1011 	}
1012 	buf = sdmalloc(Uploadsz);
1013 	if(buf == nil)
1014 		error(Enomem);
1015 	if(Firmwarecmp){
1016 		cbuf = sdmalloc(Uploadsz);
1017 		if(cbuf == nil)
1018 			error(Enomem);
1019 	}
1020 	off = 0;
1021 	for(;;){
1022 		n = devtab[c->type]->read(c, buf, Uploadsz, off);
1023 		if(n <= 0)
1024 			break;
1025 		if(isconfig){
1026 			n = condense(buf, n);
1027 			off = ctl->socramsize - n - 4;
1028 		}else if(off == 0)
1029 			memmove(ctl->resetvec.c, buf, sizeof(ctl->resetvec.c));
1030 		while(n&3)
1031 			buf[n++] = 0;
1032 		sbmem(1, buf, n, ctl->rambase + off);
1033 		if(isconfig)
1034 			break;
1035 		off += n;
1036 	}
1037 	if(Firmwarecmp){
1038 		if(FWDEBUG) print("compare...");
1039 		if(!isconfig)
1040 			off = 0;
1041 		for(;;){
1042 			if(!isconfig){
1043 				n = devtab[c->type]->read(c, buf, Uploadsz, off);
1044 				if(n <= 0)
1045 					break;
1046 			while(n&3)
1047 				buf[n++] = 0;
1048 			}
1049 			sbmem(0, cbuf, n, ctl->rambase + off);
1050 			if(memcmp(buf, cbuf, n) != 0){
1051 				print("ether4330: firmware load failed offset %d\n", off);
1052 				error(Eio);
1053 			}
1054 			if(isconfig)
1055 				break;
1056 			off += n;
1057 		}
1058 	}
1059 	if(FWDEBUG) print("\n");
1060 	poperror();
1061 	cclose(c);
1062 	sdfree(buf);
1063 	sdfree(cbuf);
1064 	return n;
1065 }
1066 
1067 /*
1068  * Upload regulatory file (.clm) to firmware.
1069  * Packet format is
1070  *	[2]flag [2]type [4]len [4]crc [len]data
1071  */
1072 static void
reguload(Ctlr * ctl,char * file)1073 reguload(Ctlr *ctl, char *file)
1074 {
1075 	Chan *c;
1076 	uchar *buf;
1077 	int off, n, flag;
1078 	enum {
1079 		Reguhdr = 2+2+4+4,
1080 		Regusz	= 1400,
1081 		Regutyp	= 2,
1082 		Flagclm	= 1<<12,
1083 		Firstpkt= 1<<1,
1084 		Lastpkt	= 1<<2,
1085 	};
1086 
1087 	buf = nil;
1088 	c = findfirmware(file);
1089 	if(waserror()){
1090 		cclose(c);
1091 		free(buf);
1092 		nexterror();
1093 	}
1094 	buf = malloc(Reguhdr+Regusz+1);
1095 	if(buf == nil)
1096 		error(Enomem);
1097 	put2(buf+2, Regutyp);
1098 	put2(buf+8, 0);
1099 	off = 0;
1100 	flag = Flagclm | Firstpkt;
1101 	while((flag&Lastpkt) == 0){
1102 		n = devtab[c->type]->read(c, buf+Reguhdr, Regusz+1, off);
1103 		if(n <= 0)
1104 			break;
1105 		if(n == Regusz+1)
1106 			--n;
1107 		else{
1108 			while(n&7)
1109 				buf[Reguhdr+n++] = 0;
1110 			flag |= Lastpkt;
1111 		}
1112 		put2(buf+0, flag);
1113 		put4(buf+4, n);
1114 		wlsetvar(ctl, "clmload", buf, Reguhdr + n);
1115 		off += n;
1116 		flag &= ~Firstpkt;
1117 	}
1118 	poperror();
1119 	cclose(c);
1120 	free(buf);
1121 }
1122 
1123 static void
fwload(Ctlr * ctl)1124 fwload(Ctlr *ctl)
1125 {
1126 	uchar buf[4];
1127 	uint i, n;
1128 
1129 	i = 0;
1130 	while(firmware[i].chipid != ctl->chipid ||
1131 		   firmware[i].chiprev != ctl->chiprev){
1132 		if(++i == nelem(firmware)){
1133 			print("ether4330: no firmware for chipid %x (%d) chiprev %d\n",
1134 				ctl->chipid, ctl->chipid, ctl->chiprev);
1135 			error("no firmware");
1136 		}
1137 	}
1138 	ctl->regufile = firmware[i].regufile;
1139 	cfgw(Clkcsr, ReqALP);
1140 	while((cfgr(Clkcsr) & ALPavail) == 0)
1141 		microdelay(10);
1142 	memset(buf, 0, 4);
1143 	sbmem(1, buf, 4, ctl->rambase + ctl->socramsize - 4);
1144 	if(FWDEBUG) print("firmware load...");
1145 	upload(ctl, firmware[i].fwfile, 0);
1146 	if(FWDEBUG) print("config load...");
1147 	n = upload(ctl, firmware[i].cfgfile, 1);
1148 	n /= 4;
1149 	n = (n & 0xFFFF) | (~n << 16);
1150 	put4(buf, n);
1151 	sbmem(1, buf, 4, ctl->rambase + ctl->socramsize - 4);
1152 	if(ctl->armcore == ARMcr4){
1153 		sbwindow(ctl->sdregs);
1154 		cfgwritel(Fn1, ctl->sdregs + Intstatus, ~0);
1155 		if(ctl->resetvec.i != 0){
1156 			if(SBDEBUG) print("%ux\n", ctl->resetvec.i);
1157 			sbmem(1, ctl->resetvec.c, sizeof(ctl->resetvec.c), 0);
1158 		}
1159 		sbreset(ctl->armctl, Cr4Cpuhalt, 0);
1160 	}else
1161 		sbreset(ctl->armctl, 0, 0);
1162 }
1163 
1164 /*
1165  * Communication of data and control packets
1166  */
1167 
1168 void
intwait(Ctlr * ctlr,int wait)1169 intwait(Ctlr *ctlr, int wait)
1170 {
1171 	ulong ints, mbox;
1172 	int i;
1173 
1174 	if(waserror())
1175 		return;
1176 	for(;;){
1177 		sdiocardintr(wait);
1178 		sbwindow(ctlr->sdregs);
1179 		i = sdiord(Fn0, Intpend);
1180 		if(i == 0){
1181 			tsleep(&up->sleep, return0, 0, 10);
1182 			continue;
1183 		}
1184 		ints = cfgreadl(Fn1, ctlr->sdregs + Intstatus);
1185 		cfgwritel(Fn1, ctlr->sdregs + Intstatus, ints);
1186 		if(0) print("INTS: (%x) %lux -> %lux\n", i, ints, cfgreadl(Fn1, ctlr->sdregs + Intstatus));
1187 		if(ints & MailboxInt){
1188 			mbox = cfgreadl(Fn1, ctlr->sdregs + Hostmboxdata);
1189 			cfgwritel(Fn1, ctlr->sdregs + Sbmbox, 2);	/* ack */
1190 			if(mbox & 0x8)
1191 				print("ether4330: firmware ready\n");
1192 		}
1193 		if(ints & FrameInt)
1194 			break;
1195 	}
1196 	poperror();
1197 }
1198 
1199 static Block*
wlreadpkt(Ctlr * ctl)1200 wlreadpkt(Ctlr *ctl)
1201 {
1202 	Block *b;
1203 	Sdpcm *p;
1204 	int len, lenck;
1205 
1206 	b = allocb(2048);
1207 	p = (Sdpcm*)b->wp;
1208 	qlock(&ctl->pktlock);
1209 	for(;;){
1210 		packetrw(0, b->wp, sizeof(*p));
1211 		len = p->len[0] | p->len[1]<<8;
1212 		if(len == 0){
1213 			freeb(b);
1214 			b = nil;
1215 			break;
1216 		}
1217 		lenck = p->lenck[0] | p->lenck[1]<<8;
1218 		if(lenck != (len ^ 0xFFFF) ||
1219 		   len < sizeof(*p) || len > 2048){
1220 			print("ether4330: wlreadpkt error len %.4x lenck %.4x\n", len, lenck);
1221 			cfgw(Framectl, Rfhalt);
1222 			while(cfgr(Rfrmcnt+1))
1223 				;
1224 			while(cfgr(Rfrmcnt))
1225 				;
1226 			continue;
1227 		}
1228 		if(len > sizeof(*p))
1229 			packetrw(0, b->wp + sizeof(*p), len - sizeof(*p));
1230 		b->wp += len;
1231 		break;
1232 	}
1233 	qunlock(&ctl->pktlock);
1234 	return b;
1235 }
1236 
1237 static void
txstart(Ether * edev)1238 txstart(Ether *edev)
1239 {
1240 	Ctlr *ctl;
1241 	Sdpcm *p;
1242 	Block *b;
1243 	int len, off;
1244 
1245 	ctl = edev->ctlr;
1246 	if(!canqlock(&ctl->tlock))
1247 		return;
1248 	if(waserror()){
1249 		qunlock(&ctl->tlock);
1250 		return;
1251 	}
1252 	for(;;){
1253 		lock(&ctl->txwinlock);
1254 		if(ctl->txseq == ctl->txwindow){
1255 			//print("f");
1256 			unlock(&ctl->txwinlock);
1257 			break;
1258 		}
1259 		if(ctl->fcmask & 1<<2){
1260 			//print("x");
1261 			unlock(&ctl->txwinlock);
1262 			break;
1263 		}
1264 		unlock(&ctl->txwinlock);
1265 		b = qget(edev->oq);
1266 		if(b == nil)
1267 			break;
1268 		off = ((uintptr)b->rp & 3) + sizeof(Sdpcm);
1269 		b = padblock(b, off + 4);
1270 		len = BLEN(b);
1271 		p = (Sdpcm*)b->rp;
1272 		memset(p, 0, off);	/* TODO: refactor dup code */
1273 		put2(p->len, len);
1274 		put2(p->lenck, ~len);
1275 		p->chanflg = 2;
1276 		p->seq = ctl->txseq;
1277 		p->doffset = off;
1278 		put4(b->rp + off, 0x20);	/* BDC header */
1279 		if(iodebug) dump("send", b->rp, len);
1280 		qlock(&ctl->pktlock);
1281 		if(waserror()){
1282 			if(iodebug) print("halt frame %x %x\n", cfgr(Wfrmcnt+1), cfgr(Wfrmcnt+1));
1283 			cfgw(Framectl, Wfhalt);
1284 			while(cfgr(Wfrmcnt+1))
1285 				;
1286 			while(cfgr(Wfrmcnt))
1287 				;
1288 			qunlock(&ctl->pktlock);
1289 			nexterror();
1290 		}
1291 		packetrw(1, b->rp, len);
1292 		ctl->txseq++;
1293 		poperror();
1294 		qunlock(&ctl->pktlock);
1295 		freeb(b);
1296 	}
1297 	poperror();
1298 	qunlock(&ctl->tlock);
1299 }
1300 
1301 static void
rproc(void * a)1302 rproc(void *a)
1303 {
1304 	Ether *edev;
1305 	Ctlr *ctl;
1306 	Block *b;
1307 	Sdpcm *p;
1308 	Cmd *q;
1309 	int flowstart;
1310 	int bdc;
1311 
1312 	edev = a;
1313 	ctl = edev->ctlr;
1314 	flowstart = 0;
1315 	for(;;){
1316 		if(flowstart){
1317 			//print("F");
1318 			flowstart = 0;
1319 			txstart(edev);
1320 		}
1321 		b = wlreadpkt(ctl);
1322 		if(b == nil){
1323 			intwait(ctl, 1);
1324 			continue;
1325 		}
1326 		p = (Sdpcm*)b->rp;
1327 		if(p->window != ctl->txwindow || p->fcmask != ctl->fcmask){
1328 			lock(&ctl->txwinlock);
1329 			if(p->window != ctl->txwindow){
1330 				if(ctl->txseq == ctl->txwindow)
1331 					flowstart = 1;
1332 				ctl->txwindow = p->window;
1333 			}
1334 			if(p->fcmask != ctl->fcmask){
1335 				if((p->fcmask & 1<<2) == 0)
1336 					flowstart = 1;
1337 				ctl->fcmask = p->fcmask;
1338 			}
1339 			unlock(&ctl->txwinlock);
1340 		}
1341 		switch(p->chanflg & 0xF){
1342 		case 0:
1343 			if(iodebug) dump("rsp", b->rp, BLEN(b));
1344 			if(BLEN(b) < sizeof(Sdpcm) + sizeof(Cmd))
1345 				break;
1346 			q = (Cmd*)(b->rp + sizeof(*p));
1347 			if((q->id[0] | q->id[1]<<8) != ctl->reqid)
1348 				break;
1349 			ctl->rsp = b;
1350 			wakeup(&ctl->cmdr);
1351 			continue;
1352 		case 1:
1353 			if(iodebug) dump("event", b->rp, BLEN(b));
1354 			if(BLEN(b) > p->doffset + 4){
1355 				bdc = 4 + (b->rp[p->doffset + 3] << 2);
1356 				if(BLEN(b) > p->doffset + bdc){
1357 					b->rp += p->doffset + bdc;	/* skip BDC header */
1358 					bcmevent(ctl, b->rp, BLEN(b));
1359 					break;
1360 				}
1361 			}
1362 			if(iodebug && BLEN(b) != p->doffset)
1363 				print("short event %ld %d\n", BLEN(b), p->doffset);
1364 			break;
1365 		case 2:
1366 			if(iodebug) dump("packet", b->rp, BLEN(b));
1367 			if(BLEN(b) > p->doffset + 4){
1368 				bdc = 4 + (b->rp[p->doffset + 3] << 2);
1369 				if(BLEN(b) >= p->doffset + bdc + ETHERHDRSIZE){
1370 					b->rp += p->doffset + bdc;	/* skip BDC header */
1371 					etheriq(edev, b, 1);
1372 					continue;
1373 				}
1374 			}
1375 			break;
1376 		default:
1377 			dump("ether4330: bad packet", b->rp, BLEN(b));
1378 			break;
1379 		}
1380 		freeb(b);
1381 	}
1382 }
1383 
1384 static void
linkdown(Ctlr * ctl)1385 linkdown(Ctlr *ctl)
1386 {
1387 	Ether *edev;
1388 	Netfile *f;
1389 	int i;
1390 
1391 	edev = ctl->edev;
1392 	if(edev == nil || ctl->status != Connected)
1393 		return;
1394 	ctl->status = Disconnected;
1395 	/* send eof to aux/wpa */
1396 	for(i = 0; i < edev->nfile; i++){
1397 		f = edev->f[i];
1398 		if(f == nil || f->in == nil || f->inuse == 0 || f->type != 0x888e)
1399 			continue;
1400 		qwrite(f->in, 0, 0);
1401 	}
1402 }
1403 
1404 /*
1405  * Command interface between host and firmware
1406  */
1407 
1408 static char *eventnames[] = {
1409 	[0] = "set ssid",
1410 	[1] = "join",
1411 	[2] = "start",
1412 	[3] = "auth",
1413 	[4] = "auth ind",
1414 	[5] = "deauth",
1415 	[6] = "deauth ind",
1416 	[7] = "assoc",
1417 	[8] = "assoc ind",
1418 	[9] = "reassoc",
1419 	[10] = "reassoc ind",
1420 	[11] = "disassoc",
1421 	[12] = "disassoc ind",
1422 	[13] = "quiet start",
1423 	[14] = "quiet end",
1424 	[15] = "beacon rx",
1425 	[16] = "link",
1426 	[17] = "mic error",
1427 	[18] = "ndis link",
1428 	[19] = "roam",
1429 	[20] = "txfail",
1430 	[21] = "pmkid cache",
1431 	[22] = "retrograde tsf",
1432 	[23] = "prune",
1433 	[24] = "autoauth",
1434 	[25] = "eapol msg",
1435 	[26] = "scan complete",
1436 	[27] = "addts ind",
1437 	[28] = "delts ind",
1438 	[29] = "bcnsent ind",
1439 	[30] = "bcnrx msg",
1440 	[31] = "bcnlost msg",
1441 	[32] = "roam prep",
1442 	[33] = "pfn net found",
1443 	[34] = "pfn net lost",
1444 	[35] = "reset complete",
1445 	[36] = "join start",
1446 	[37] = "roam start",
1447 	[38] = "assoc start",
1448 	[39] = "ibss assoc",
1449 	[40] = "radio",
1450 	[41] = "psm watchdog",
1451 	[44] = "probreq msg",
1452 	[45] = "scan confirm ind",
1453 	[46] = "psk sup",
1454 	[47] = "country code changed",
1455 	[48] = "exceeded medium time",
1456 	[49] = "icv error",
1457 	[50] = "unicast decode error",
1458 	[51] = "multicast decode error",
1459 	[52] = "trace",
1460 	[53] = "bta hci event",
1461 	[54] = "if",
1462 	[55] = "p2p disc listen complete",
1463 	[56] = "rssi",
1464 	[57] = "pfn scan complete",
1465 	[58] = "extlog msg",
1466 	[59] = "action frame",
1467 	[60] = "action frame complete",
1468 	[61] = "pre assoc ind",
1469 	[62] = "pre reassoc ind",
1470 	[63] = "channel adopted",
1471 	[64] = "ap started",
1472 	[65] = "dfs ap stop",
1473 	[66] = "dfs ap resume",
1474 	[67] = "wai sta event",
1475 	[68] = "wai msg",
1476 	[69] = "escan result",
1477 	[70] = "action frame off chan complete",
1478 	[71] = "probresp msg",
1479 	[72] = "p2p probreq msg",
1480 	[73] = "dcs request",
1481 	[74] = "fifo credit map",
1482 	[75] = "action frame rx",
1483 	[76] = "wake event",
1484 	[77] = "rm complete",
1485 	[78] = "htsfsync",
1486 	[79] = "overlay req",
1487 	[80] = "csa complete ind",
1488 	[81] = "excess pm wake event",
1489 	[82] = "pfn scan none",
1490 	[83] = "pfn scan allgone",
1491 	[84] = "gtk plumbed",
1492 	[85] = "assoc ind ndis",
1493 	[86] = "reassoc ind ndis",
1494 	[87] = "assoc req ie",
1495 	[88] = "assoc resp ie",
1496 	[89] = "assoc recreated",
1497 	[90] = "action frame rx ndis",
1498 	[91] = "auth req",
1499 	[92] = "tdls peer event",
1500 	[127] = "bcmc credit support"
1501 };
1502 
1503 static char*
evstring(uint event)1504 evstring(uint event)
1505 {
1506 	static char buf[12];
1507 
1508 	if(event >= nelem(eventnames) || eventnames[event] == 0){
1509 		/* not reentrant but only called from one kproc */
1510 		snprint(buf, sizeof buf, "%d", event);
1511 		return buf;
1512 	}
1513 	return eventnames[event];
1514 }
1515 
1516 static void
bcmevent(Ctlr * ctl,uchar * p,int len)1517 bcmevent(Ctlr *ctl, uchar *p, int len)
1518 {
1519 	int flags;
1520 	long event, status, reason;
1521 
1522 	if(len < ETHERHDRSIZE + 10 + 46)
1523 		return;
1524 	p += ETHERHDRSIZE + 10;			/* skip bcm_ether header */
1525 	len -= ETHERHDRSIZE + 10;
1526 	flags = nhgets(p + 2);
1527 	event = nhgets(p + 6);
1528 	status = nhgetl(p + 8);
1529 	reason = nhgetl(p + 12);
1530 	if(EVENTDEBUG)
1531 		print("ether4330: [%s] status %ld flags %#x reason %ld\n",
1532 			evstring(event), status, flags, reason);
1533 	switch(event){
1534 	case 19:	/* E_ROAM */
1535 		if(status == 0)
1536 			break;
1537 	/* fall through */
1538 	case 0:		/* E_SET_SSID */
1539 		ctl->joinstatus = 1 + status;
1540 		wakeup(&ctl->joinr);
1541 		break;
1542 	case 16:	/* E_LINK */
1543 		if(flags&1)	/* link up */
1544 			break;
1545 	/* fall through */
1546 	case 5:		/* E_DEAUTH */
1547 	case 6:		/* E_DEAUTH_IND */
1548 	case 12:	/* E_DISASSOC_IND */
1549 		linkdown(ctl);
1550 		break;
1551 	case 26:	/* E_SCAN_COMPLETE */
1552 		break;
1553 	case 69:	/* E_ESCAN_RESULT */
1554 		wlscanresult(ctl->edev, p + 48, len - 48);
1555 		break;
1556 	default:
1557 		if(status){
1558 			if(!EVENTDEBUG)
1559 				print("ether4330: [%s] error status %ld flags %#x reason %ld\n",
1560 					evstring(event), status, flags, reason);
1561 			dump("event", p, len);
1562 		}
1563 	}
1564 }
1565 
1566 static int
joindone(void * a)1567 joindone(void *a)
1568 {
1569 	return ((Ctlr*)a)->joinstatus;
1570 }
1571 
1572 static int
waitjoin(Ctlr * ctl)1573 waitjoin(Ctlr *ctl)
1574 {
1575 	int n;
1576 
1577 	sleep(&ctl->joinr, joindone, ctl);
1578 	n = ctl->joinstatus;
1579 	ctl->joinstatus = 0;
1580 	return n - 1;
1581 }
1582 
1583 static int
cmddone(void * a)1584 cmddone(void *a)
1585 {
1586 	return ((Ctlr*)a)->rsp != nil;
1587 }
1588 
1589 static void
wlcmd(Ctlr * ctl,int write,int op,void * data,int dlen,void * res,int rlen)1590 wlcmd(Ctlr *ctl, int write, int op, void *data, int dlen, void *res, int rlen)
1591 {
1592 	Block *b;
1593 	Sdpcm *p;
1594 	Cmd *q;
1595 	int len, tlen;
1596 
1597 	if(write)
1598 		tlen = dlen + rlen;
1599 	else
1600 		tlen = MAX(dlen, rlen);
1601 	len = sizeof(Sdpcm) + sizeof(Cmd) + tlen;
1602 	b = allocb(len);
1603 	qlock(&ctl->cmdlock);
1604 	if(waserror()){
1605 		freeb(b);
1606 		qunlock(&ctl->cmdlock);
1607 		nexterror();
1608 	}
1609 	memset(b->wp, 0, len);
1610 	qlock(&ctl->pktlock);
1611 	p = (Sdpcm*)b->wp;
1612 	put2(p->len, len);
1613 	put2(p->lenck, ~len);
1614 	p->seq = ctl->txseq;
1615 	p->doffset = sizeof(Sdpcm);
1616 	b->wp += sizeof(*p);
1617 
1618 	q = (Cmd*)b->wp;
1619 	put4(q->cmd, op);
1620 	put4(q->len, tlen);
1621 	put2(q->flags, write? 2 : 0);
1622 	put2(q->id, ++ctl->reqid);
1623 	put4(q->status, 0);
1624 	b->wp += sizeof(*q);
1625 
1626 	if(dlen > 0)
1627 		memmove(b->wp, data, dlen);
1628 	if(write)
1629 		memmove(b->wp + dlen, res, rlen);
1630 	b->wp += tlen;
1631 
1632 	if(iodebug) dump("cmd", b->rp, len);
1633 	packetrw(1, b->rp, len);
1634 	ctl->txseq++;
1635 	qunlock(&ctl->pktlock);
1636 	freeb(b);
1637 	b = nil;
1638 	USED(b);
1639 	sleep(&ctl->cmdr, cmddone, ctl);
1640 	b = ctl->rsp;
1641 	ctl->rsp = nil;
1642 	assert(b != nil);
1643 	p = (Sdpcm*)b->rp;
1644 	q = (Cmd*)(b->rp + p->doffset);
1645 	if(q->status[0] | q->status[1] | q->status[2] | q->status[3]){
1646 		print("ether4330: cmd %d error status %ld\n", op, get4(q->status));
1647 		dump("ether4330: cmd error", b->rp, BLEN(b));
1648 		error("wlcmd error");
1649 	}
1650 	if(!write)
1651 		memmove(res, q + 1, rlen);
1652 	freeb(b);
1653 	qunlock(&ctl->cmdlock);
1654 	poperror();
1655 }
1656 
1657 static void
wlcmdint(Ctlr * ctl,int op,int val)1658 wlcmdint(Ctlr *ctl, int op, int val)
1659 {
1660 	uchar buf[4];
1661 
1662 	put4(buf, val);
1663 	wlcmd(ctl, 1, op, buf, 4, nil, 0);
1664 }
1665 
1666 static void
wlgetvar(Ctlr * ctl,char * name,void * val,int len)1667 wlgetvar(Ctlr *ctl, char *name, void *val, int len)
1668 {
1669 	wlcmd(ctl, 0, GetVar, name, strlen(name) + 1, val, len);
1670 }
1671 
1672 static void
wlsetvar(Ctlr * ctl,char * name,void * val,int len)1673 wlsetvar(Ctlr *ctl, char *name, void *val, int len)
1674 {
1675 	if(VARDEBUG){
1676 		char buf[32];
1677 		snprint(buf, sizeof buf, "wlsetvar %s:", name);
1678 		dump(buf, val, len);
1679 	}
1680 	wlcmd(ctl, 1, SetVar, name, strlen(name) + 1, val, len);
1681 }
1682 
1683 static void
wlsetint(Ctlr * ctl,char * name,int val)1684 wlsetint(Ctlr *ctl, char *name, int val)
1685 {
1686 	uchar buf[4];
1687 
1688 	put4(buf, val);
1689 	wlsetvar(ctl, name, buf, 4);
1690 }
1691 
1692 static void
wlwepkey(Ctlr * ctl,int i)1693 wlwepkey(Ctlr *ctl, int i)
1694 {
1695 	uchar params[164];
1696 	uchar *p;
1697 
1698 	memset(params, 0, sizeof params);
1699 	p = params;
1700 	p = put4(p, i);		/* index */
1701 	p = put4(p, ctl->keys[i].len);
1702 	memmove(p, ctl->keys[i].dat, ctl->keys[i].len);
1703 	p += 32 + 18*4;		/* keydata, pad */
1704 	if(ctl->keys[i].len == WMinKeyLen)
1705 		p = put4(p, 1);		/* algo = WEP1 */
1706 	else
1707 		p = put4(p, 3);		/* algo = WEP128 */
1708 	put4(p, 2);		/* flags = Primarykey */
1709 
1710 	wlsetvar(ctl, "wsec_key", params, sizeof params);
1711 }
1712 
1713 static void
memreverse(char * dst,char * src,int len)1714 memreverse(char *dst, char *src, int len)
1715 {
1716 	src += len;
1717 	while(len-- > 0)
1718 		*dst++ = *--src;
1719 }
1720 
1721 static void
wlwpakey(Ctlr * ctl,int id,uvlong iv,uchar * ea)1722 wlwpakey(Ctlr *ctl, int id, uvlong iv, uchar *ea)
1723 {
1724 	uchar params[164];
1725 	uchar *p;
1726 	int pairwise;
1727 
1728 	if(id == CMrxkey)
1729 		return;
1730 	pairwise = (id == CMrxkey || id == CMtxkey);
1731 	memset(params, 0, sizeof params);
1732 	p = params;
1733 	if(pairwise)
1734 		p = put4(p, 0);
1735 	else
1736 		p = put4(p, id - CMrxkey0);	/* group key id */
1737 	p = put4(p, ctl->keys[0].len);
1738 	memmove((char*)p,  ctl->keys[0].dat, ctl->keys[0].len);
1739 	p += 32 + 18*4;		/* keydata, pad */
1740 	if(ctl->cryptotype == Wpa)
1741 		p = put4(p, 2);	/* algo = TKIP */
1742 	else
1743 		p = put4(p, 4);	/* algo = AES_CCM */
1744 	if(pairwise)
1745 		p = put4(p, 0);
1746 	else
1747 		p = put4(p, 2);		/* flags = Primarykey */
1748 	p += 3*4;
1749 	p = put4(p, 0); //pairwise);		/* iv initialised */
1750 	p += 4;
1751 	p = put4(p, iv>>16);	/* iv high */
1752 	p = put2(p, iv&0xFFFF);	/* iv low */
1753 	p += 2 + 2*4;		/* align, pad */
1754 	if(pairwise)
1755 		memmove(p, ea, Eaddrlen);
1756 
1757 	wlsetvar(ctl, "wsec_key", params, sizeof params);
1758 }
1759 
1760 static void
wljoin(Ctlr * ctl,char * ssid,int chan)1761 wljoin(Ctlr *ctl, char *ssid, int chan)
1762 {
1763 	uchar params[72];
1764 	uchar *p;
1765 	int n;
1766 
1767 	if(chan != 0)
1768 		chan |= 0x2b00;		/* 20Mhz channel width */
1769 	p = params;
1770 	n = strlen(ssid);
1771 	n = MIN(n, 32);
1772 	p = put4(p, n);
1773 	memmove(p, ssid, n);
1774 	memset(p + n, 0, 32 - n);
1775 	p += 32;
1776 	p = put4(p, 0xff);	/* scan type */
1777 	if(chan != 0){
1778 		p = put4(p, 2);		/* num probes */
1779 		p = put4(p, 120);	/* active time */
1780 		p = put4(p, 390);	/* passive time */
1781 	}else{
1782 		p = put4(p, -1);	/* num probes */
1783 		p = put4(p, -1);	/* active time */
1784 		p = put4(p, -1);	/* passive time */
1785 	}
1786 	p = put4(p, -1);	/* home time */
1787 	memset(p, 0xFF, Eaddrlen);	/* bssid */
1788 	p += Eaddrlen;
1789 	p = put2(p, 0);		/* pad */
1790 	if(chan != 0){
1791 		p = put4(p, 1);		/* num chans */
1792 		p = put2(p, chan);	/* chan spec */
1793 		p = put2(p, 0);		/* pad */
1794 		assert(p == params + sizeof(params));
1795 	}else{
1796 		p = put4(p, 0);		/* num chans */
1797 		assert(p == params + sizeof(params) - 4);
1798 	}
1799 
1800 	wlsetvar(ctl, "join", params, chan? sizeof params : sizeof params - 4);
1801 	ctl->status = Connecting;
1802 	switch(waitjoin(ctl)){
1803 		case 0:
1804 			ctl->status = Connected;
1805 			break;
1806 		case 3:
1807 			ctl->status = Disconnected;
1808 			error("wifi join: network not found");
1809 		case 1:
1810 			ctl->status = Disconnected;
1811 			error("wifi join: failed");
1812 		default:
1813 			ctl->status = Disconnected;
1814 			error("wifi join: error");
1815 	}
1816 }
1817 
1818 static void
wlscanstart(Ctlr * ctl)1819 wlscanstart(Ctlr *ctl)
1820 {
1821 	/* version[4] action[2] sync_id[2] ssidlen[4] ssid[32] bssid[6] bss_type[1]
1822 		scan_type[1] nprobes[4] active_time[4] passive_time[4] home_time[4]
1823 		nchans[2] nssids[2] chans[nchans][2] ssids[nssids][32] */
1824 	/* hack - this is only correct on a little-endian cpu */
1825 	static uchar params[4+2+2+4+32+6+1+1+4*4+2+2+14*2+32+4] = {
1826 		1,0,0,0,
1827 		1,0,
1828 		0x34,0x12,
1829 		0,0,0,0,
1830 		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,
1831 		0xff,0xff,0xff,0xff,0xff,0xff,
1832 		2,
1833 		0,
1834 		0xff,0xff,0xff,0xff,
1835 		0xff,0xff,0xff,0xff,
1836 		0xff,0xff,0xff,0xff,
1837 		0xff,0xff,0xff,0xff,
1838 		14,0,
1839 		1,0,
1840 		0x01,0x2b,0x02,0x2b,0x03,0x2b,0x04,0x2b,0x05,0x2e,0x06,0x2e,0x07,0x2e,
1841 		0x08,0x2b,0x09,0x2b,0x0a,0x2b,0x0b,0x2b,0x0c,0x2b,0x0d,0x2b,0x0e,0x2b,
1842 		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,
1843 	};
1844 
1845 	wlcmdint(ctl, 49, 0);	/* PASSIVE_SCAN */
1846 	wlsetvar(ctl, "escan", params, sizeof params);
1847 }
1848 
1849 static uchar*
gettlv(uchar * p,uchar * ep,int tag)1850 gettlv(uchar *p, uchar *ep, int tag)
1851 {
1852 	int len;
1853 
1854 	while(p + 1 < ep){
1855 		len = p[1];
1856 		if(p + 2 + len > ep)
1857 			return nil;
1858 		if(p[0] == tag)
1859 			return p;
1860 		p += 2 + len;
1861 	}
1862 	return nil;
1863 }
1864 
1865 static void
addscan(Block * bp,uchar * p,int len)1866 addscan(Block *bp, uchar *p, int len)
1867 {
1868 	char bssid[24];
1869 	char *auth, *auth2;
1870 	uchar *t, *et;
1871 	int ielen;
1872 	static uchar wpaie1[4] = { 0x00, 0x50, 0xf2, 0x01 };
1873 
1874 	snprint(bssid, sizeof bssid, ";bssid=%E", p + 8);
1875 	if(strstr((char*)bp->rp, bssid) != nil)
1876 		return;
1877 	bp->wp = (uchar*)seprint((char*)bp->wp, (char*)bp->lim,
1878 		"ssid=%.*s%s;signal=%d;noise=%d;chan=%d",
1879 		p[18], (char*)p+19, bssid,
1880 		(short)get2(p+78), (signed char)p[80],
1881 		get2(p+72) & 0xF);
1882 	auth = auth2 = "";
1883 	if(get2(p + 16) & 0x10)
1884 		auth = ";wep";
1885 	ielen = get4(p + 0x78);
1886 	if(ielen > 0){
1887 		t = p + get4(p + 0x74);
1888 		et = t + ielen;
1889 		if(et > p + len)
1890 			return;
1891 		if(gettlv(t, et, 0x30) != nil){
1892 			auth = "";
1893 			auth2 = ";wpa2";
1894 		}
1895 		while((t = gettlv(t, et, 0xdd)) != nil){
1896 			if(t[1] > 4 && memcmp(t+2, wpaie1, 4) == 0){
1897 				auth = ";wpa";
1898 				break;
1899 			}
1900 			t += 2 + t[1];
1901 		}
1902 	}
1903 	bp->wp = (uchar*)seprint((char*)bp->wp, (char*)bp->lim,
1904 		"%s%s\n", auth, auth2);
1905 }
1906 
1907 
1908 static void
wlscanresult(Ether * edev,uchar * p,int len)1909 wlscanresult(Ether *edev, uchar *p, int len)
1910 {
1911 	Ctlr *ctlr;
1912 	Netfile **ep, *f, **fp;
1913 	Block *bp;
1914 	int nbss, i;
1915 
1916 	ctlr = edev->ctlr;
1917 	if(get4(p) > len)
1918 		return;
1919 	/* TODO: more syntax checking */
1920 	bp = ctlr->scanb;
1921 	if(bp == nil)
1922 		ctlr->scanb = bp = allocb(8192);
1923 	nbss = get2(p+10);
1924 	p += 12;
1925 	len -= 12;
1926 	if(0) dump("SCAN", p, len);
1927 	if(nbss){
1928 		addscan(bp, p, len);
1929 		return;
1930 	}
1931 	i = edev->scan;
1932 	ep = &edev->f[Ntypes];
1933 	for(fp = edev->f; fp < ep && i > 0; fp++){
1934 		f = *fp;
1935 		if(f == nil || f->scan == 0)
1936 			continue;
1937 		if(i == 1)
1938 			qpass(f->in, bp);
1939 		else
1940 			qpass(f->in, copyblock(bp, BLEN(bp)));
1941 		i--;
1942 	}
1943 	if(i)
1944 		freeb(bp);
1945 	ctlr->scanb = nil;
1946 }
1947 
1948 static void
lproc(void * a)1949 lproc(void *a)
1950 {
1951 	Ether *edev;
1952 	Ctlr *ctlr;
1953 	int secs;
1954 
1955 	edev = a;
1956 	ctlr = edev->ctlr;
1957 	secs = 0;
1958 	for(;;){
1959 		tsleep(&up->sleep, return0, 0, 1000);
1960 		if(ctlr->scansecs){
1961 			if(secs == 0){
1962 				if(waserror())
1963 					ctlr->scansecs = 0;
1964 				else{
1965 					wlscanstart(ctlr);
1966 					poperror();
1967 				}
1968 				secs = ctlr->scansecs;
1969 			}
1970 			--secs;
1971 		}else
1972 			secs = 0;
1973 	}
1974 }
1975 
1976 static void
wlinit(Ether * edev,Ctlr * ctlr)1977 wlinit(Ether *edev, Ctlr *ctlr)
1978 {
1979 	uchar ea[Eaddrlen];
1980 	uchar eventmask[16];
1981 	char version[128];
1982 	char *p;
1983 	static uchar keepalive[12] = {1, 0, 11, 0, 0xd8, 0xd6, 0, 0, 0, 0, 0, 0};
1984 
1985 	wlgetvar(ctlr, "cur_etheraddr", ea, Eaddrlen);
1986 	memmove(edev->ea, ea, Eaddrlen);
1987 	memmove(edev->addr, ea, Eaddrlen);
1988 	print("ether4330: addr %E\n", edev->ea);
1989 	wlsetint(ctlr, "assoc_listen", 10);
1990 	if(ctlr->chipid == 43430 || ctlr->chipid == 0x4345)
1991 		wlcmdint(ctlr, 0x56, 0);	/* powersave off */
1992 	else
1993 		wlcmdint(ctlr, 0x56, 2);	/* powersave FAST */
1994 	wlsetint(ctlr, "bus:txglom", 0);
1995 	wlsetint(ctlr, "bcn_timeout", 10);
1996 	wlsetint(ctlr, "assoc_retry_max", 3);
1997 	if(ctlr->chipid == 0x4330){
1998 		wlsetint(ctlr, "btc_wire", 4);
1999 		wlsetint(ctlr, "btc_mode", 1);
2000 		wlsetvar(ctlr, "mkeep_alive", keepalive, 11);
2001 	}
2002 	memset(eventmask, 0xFF, sizeof eventmask);
2003 #define ENABLE(n)	eventmask[n/8] |= 1<<(n%8)
2004 #define DISABLE(n)	eventmask[n/8] &= ~(1<<(n%8))
2005 	DISABLE(40);	/* E_RADIO */
2006 	DISABLE(44);	/* E_PROBREQ_MSG */
2007 	DISABLE(54);	/* E_IF */
2008 	DISABLE(71);	/* E_PROBRESP_MSG */
2009 	DISABLE(20);	/* E_TXFAIL */
2010 	DISABLE(124);	/* ? */
2011 	wlsetvar(ctlr, "event_msgs", eventmask, sizeof eventmask);
2012 	wlcmdint(ctlr, 0xb9, 0x28);	/* SET_SCAN_CHANNEL_TIME */
2013 	wlcmdint(ctlr, 0xbb, 0x28);	/* SET_SCAN_UNASSOC_TIME */
2014 	wlcmdint(ctlr, 0x102, 0x82);	/* SET_SCAN_PASSIVE_TIME */
2015 	wlcmdint(ctlr, 2, 0);		/* UP */
2016 	memset(version, 0, sizeof version);
2017 	wlgetvar(ctlr, "ver", version, sizeof version - 1);
2018 	if((p = strchr(version, '\n')) != nil)
2019 		*p = '\0';
2020 	if(0) print("ether4330: %s\n", version);
2021 	wlsetint(ctlr, "roam_off", 1);
2022 	wlcmdint(ctlr, 0x14, 1);	/* SET_INFRA 1 */
2023 	wlcmdint(ctlr, 10, 0);		/* SET_PROMISC */
2024 	//wlcmdint(ctlr, 0x8e, 0);	/* SET_BAND 0 */
2025 	//wlsetint(ctlr, "wsec", 1);
2026 	wlcmdint(ctlr, 2, 1);		/* UP */
2027 	ctlr->keys[0].len = WMinKeyLen;
2028 	//wlwepkey(ctlr, 0);
2029 }
2030 
2031 /*
2032  * Plan 9 driver interface
2033  */
2034 
2035 static long
etherbcmifstat(Ether * edev,void * a,long n,ulong offset)2036 etherbcmifstat(Ether* edev, void* a, long n, ulong offset)
2037 {
2038 	Ctlr *ctlr;
2039 	char *p;
2040 	int l;
2041 	static char *cryptoname[4] = {
2042 		[0]	"off",
2043 		[Wep]	"wep",
2044 		[Wpa]	"wpa",
2045 		[Wpa2]	"wpa2",
2046 	};
2047 	/* these strings are known by aux/wpa */
2048 	static char* connectstate[] = {
2049 		[Disconnected]	= "unassociated",
2050 		[Connecting] = "connecting",
2051 		[Connected] = "associated",
2052 	};
2053 
2054 	ctlr = edev->ctlr;
2055 	if(ctlr == nil)
2056 		return 0;
2057 	p = malloc(READSTR);
2058 	l = 0;
2059 
2060 	l += snprint(p+l, READSTR-l, "channel: %d\n", ctlr->chanid);
2061 	l += snprint(p+l, READSTR-l, "essid: %s\n", ctlr->essid);
2062 	l += snprint(p+l, READSTR-l, "crypt: %s\n", cryptoname[ctlr->cryptotype]);
2063 	l += snprint(p+l, READSTR-l, "oq: %d\n", qlen(edev->oq));
2064 	l += snprint(p+l, READSTR-l, "txwin: %d\n", ctlr->txwindow);
2065 	l += snprint(p+l, READSTR-l, "txseq: %d\n", ctlr->txseq);
2066 	l += snprint(p+l, READSTR-l, "status: %s\n", connectstate[ctlr->status]);
2067 	USED(l);
2068 	n = readstr(offset, a, n, p);
2069 	free(p);
2070 	return n;
2071 }
2072 
2073 static void
etherbcmtransmit(Ether * edev)2074 etherbcmtransmit(Ether *edev)
2075 {
2076 	Ctlr *ctlr;
2077 
2078 	ctlr = edev->ctlr;
2079 	if(ctlr == nil)
2080 		return;
2081 	txstart(edev);
2082 }
2083 
2084 static int
parsehex(char * buf,int buflen,char * a)2085 parsehex(char *buf, int buflen, char *a)
2086 {
2087 	int i, k, n;
2088 
2089 	k = 0;
2090 	for(i = 0;k < buflen && *a; i++){
2091 		if(*a >= '0' && *a <= '9')
2092 			n = *a++ - '0';
2093 		else if(*a >= 'a' && *a <= 'f')
2094 			n = *a++ - 'a' + 10;
2095 		else if(*a >= 'A' && *a <= 'F')
2096 			n = *a++ - 'A' + 10;
2097 		else
2098 			break;
2099 
2100 		if(i & 1){
2101 			buf[k] |= n;
2102 			k++;
2103 		}
2104 		else
2105 			buf[k] = n<<4;
2106 	}
2107 	if(i & 1)
2108 		return -1;
2109 	return k;
2110 }
2111 
2112 static int
wepparsekey(WKey * key,char * a)2113 wepparsekey(WKey* key, char* a)
2114 {
2115 	int i, k, len, n;
2116 	char buf[WMaxKeyLen];
2117 
2118 	len = strlen(a);
2119 	if(len == WMinKeyLen || len == WMaxKeyLen){
2120 		memset(key->dat, 0, sizeof(key->dat));
2121 		memmove(key->dat, a, len);
2122 		key->len = len;
2123 
2124 		return 0;
2125 	}
2126 	else if(len == WMinKeyLen*2 || len == WMaxKeyLen*2){
2127 		k = 0;
2128 		for(i = 0; i < len; i++){
2129 			if(*a >= '0' && *a <= '9')
2130 				n = *a++ - '0';
2131 			else if(*a >= 'a' && *a <= 'f')
2132 				n = *a++ - 'a' + 10;
2133 			else if(*a >= 'A' && *a <= 'F')
2134 				n = *a++ - 'A' + 10;
2135 			else
2136 				return -1;
2137 
2138 			if(i & 1){
2139 				buf[k] |= n;
2140 				k++;
2141 			}
2142 			else
2143 				buf[k] = n<<4;
2144 		}
2145 
2146 		memset(key->dat, 0, sizeof(key->dat));
2147 		memmove(key->dat, buf, k);
2148 		key->len = k;
2149 
2150 		return 0;
2151 	}
2152 
2153 	return -1;
2154 }
2155 
2156 static int
wpaparsekey(WKey * key,uvlong * ivp,char * a)2157 wpaparsekey(WKey *key, uvlong *ivp, char *a)
2158 {
2159 	int len;
2160 	char *e;
2161 
2162 	if(cistrncmp(a, "tkip:", 5) == 0 || cistrncmp(a, "ccmp:", 5) == 0)
2163 		a += 5;
2164 	else
2165 		return 1;
2166 	len = parsehex(key->dat, sizeof(key->dat), a);
2167 	if(len <= 0)
2168 		return 1;
2169 	key->len = len;
2170 	a += 2*len;
2171 	if(*a++ != '@')
2172 		return 1;
2173 	*ivp = strtoull(a, &e, 16);
2174 	if(e == a)
2175 		return -1;
2176 	return 0;
2177 }
2178 
2179 static void
setauth(Ctlr * ctlr,Cmdbuf * cb,char * a)2180 setauth(Ctlr *ctlr, Cmdbuf *cb, char *a)
2181 {
2182 	uchar wpaie[32];
2183 	int i;
2184 
2185 	i = parsehex((char*)wpaie, sizeof wpaie, a);
2186 	if(i < 2 || i != wpaie[1] + 2)
2187 		cmderror(cb, "bad wpa ie syntax");
2188 	if(wpaie[0] == 0xdd)
2189 		ctlr->cryptotype = Wpa;
2190 	else if(wpaie[0] == 0x30)
2191 		ctlr->cryptotype = Wpa2;
2192 	else
2193 		cmderror(cb, "bad wpa ie");
2194 	wlsetvar(ctlr, "wpaie", wpaie, i);
2195 	if(ctlr->cryptotype == Wpa){
2196 		wlsetint(ctlr, "wpa_auth", 4|2);	/* auth_psk | auth_unspecified */
2197 		wlsetint(ctlr, "auth", 0);
2198 		wlsetint(ctlr, "wsec", 2);		/* tkip */
2199 		wlsetint(ctlr, "wpa_auth", 4);		/* auth_psk */
2200 	}else{
2201 		wlsetint(ctlr, "wpa_auth", 0x80|0x40);	/* auth_psk | auth_unspecified */
2202 		wlsetint(ctlr, "auth", 0);
2203 		wlsetint(ctlr, "wsec", 4);		/* aes */
2204 		wlsetint(ctlr, "wpa_auth", 0x80);	/* auth_psk */
2205 	}
2206 }
2207 
2208 static int
setcrypt(Ctlr * ctlr,Cmdbuf *,char * a)2209 setcrypt(Ctlr *ctlr, Cmdbuf*, char *a)
2210 {
2211 	if(cistrcmp(a, "wep") == 0 || cistrcmp(a, "on") == 0)
2212 		ctlr->cryptotype = Wep;
2213 	else if(cistrcmp(a, "off") == 0 || cistrcmp(a, "none") == 0)
2214 		ctlr->cryptotype = 0;
2215 	else
2216 		return 0;
2217 	wlsetint(ctlr, "auth", ctlr->cryptotype);
2218 	return 1;
2219 }
2220 
2221 static long
etherbcmctl(Ether * edev,void * buf,long n)2222 etherbcmctl(Ether* edev, void* buf, long n)
2223 {
2224 	Ctlr *ctlr;
2225 	Cmdbuf *cb;
2226 	Cmdtab *ct;
2227 	uchar ea[Eaddrlen];
2228 	uvlong iv;
2229 	int i;
2230 
2231 	if((ctlr = edev->ctlr) == nil)
2232 		error(Enonexist);
2233 	USED(ctlr);
2234 
2235 	cb = parsecmd(buf, n);
2236 	if(waserror()){
2237 		free(cb);
2238 		nexterror();
2239 	}
2240 	ct = lookupcmd(cb, cmds, nelem(cmds));
2241 	switch(ct->index){
2242 	case CMauth:
2243 		setauth(ctlr, cb, cb->f[1]);
2244 		if(ctlr->essid[0])
2245 			wljoin(ctlr, ctlr->essid, ctlr->chanid);
2246 		break;
2247 	case CMchannel:
2248 		if((i = atoi(cb->f[1])) < 0 || i > 16)
2249 			cmderror(cb, "bad channel number");
2250 		//wlcmdint(ctlr, 30, i);	/* SET_CHANNEL */
2251 		ctlr->chanid = i;
2252 		break;
2253 	case CMcrypt:
2254 		if(setcrypt(ctlr, cb, cb->f[1])){
2255 			if(ctlr->essid[0])
2256 				wljoin(ctlr, ctlr->essid, ctlr->chanid);
2257 		}else
2258 			cmderror(cb, "bad crypt type");
2259 		break;
2260 	case CMessid:
2261 		if(cistrcmp(cb->f[1], "default") == 0)
2262 			memset(ctlr->essid, 0, sizeof(ctlr->essid));
2263 		else{
2264 			strncpy(ctlr->essid, cb->f[1], sizeof(ctlr->essid) - 1);
2265 			ctlr->essid[sizeof(ctlr->essid) - 1] = '\0';
2266 		}
2267 		if(!waserror()){
2268 			wljoin(ctlr, ctlr->essid, ctlr->chanid);
2269 			poperror();
2270 		}
2271 		break;
2272 	case CMjoin:	/* join essid channel wep|on|off|wpakey */
2273 		if(strcmp(cb->f[1], "") != 0){	/* empty string for no change */
2274 			if(cistrcmp(cb->f[1], "default") != 0){
2275 				strncpy(ctlr->essid, cb->f[1], sizeof(ctlr->essid)-1);
2276 				ctlr->essid[sizeof(ctlr->essid)-1] = 0;
2277 			}else
2278 				memset(ctlr->essid, 0, sizeof(ctlr->essid));
2279 		}else if(ctlr->essid[0] == 0)
2280 			cmderror(cb, "essid not set");
2281 		if((i = atoi(cb->f[2])) >= 0 && i <= 16)
2282 			ctlr->chanid = i;
2283 		else
2284 			cmderror(cb, "bad channel number");
2285 		if(!setcrypt(ctlr, cb, cb->f[3]))
2286 			setauth(ctlr, cb, cb->f[3]);
2287 		if(ctlr->essid[0])
2288 			wljoin(ctlr, ctlr->essid, ctlr->chanid);
2289 		break;
2290 	case CMkey1:
2291 	case CMkey2:
2292 	case CMkey3:
2293 	case CMkey4:
2294 		i = ct->index - CMkey1;
2295 		if(wepparsekey(&ctlr->keys[i], cb->f[1]))
2296 			cmderror(cb, "bad WEP key syntax");
2297 		wlsetint(ctlr, "wsec", 1);	/* wep enabled */
2298 		wlwepkey(ctlr, i);
2299 		break;
2300 	case CMrxkey:
2301 	case CMrxkey0:
2302 	case CMrxkey1:
2303 	case CMrxkey2:
2304 	case CMrxkey3:
2305 	case CMtxkey:
2306 		if(parseether(ea, cb->f[1]) < 0)
2307 			cmderror(cb, "bad ether addr");
2308 		if(wpaparsekey(&ctlr->keys[0], &iv, cb->f[2]))
2309 			cmderror(cb, "bad wpa key");
2310 		wlwpakey(ctlr, ct->index, iv, ea);
2311 		break;
2312 	case CMdebug:
2313 		iodebug = atoi(cb->f[1]);
2314 		break;
2315 	}
2316 	poperror();
2317 	free(cb);
2318 	return n;
2319 }
2320 
2321 static void
etherbcmscan(void * a,uint secs)2322 etherbcmscan(void *a, uint secs)
2323 {
2324 	Ether* edev;
2325 	Ctlr* ctlr;
2326 
2327 	edev = a;
2328 	ctlr = edev->ctlr;
2329 	ctlr->scansecs = secs;
2330 }
2331 
2332 static void
etherbcmattach(Ether * edev)2333 etherbcmattach(Ether* edev)
2334 {
2335 	Ctlr *ctlr;
2336 
2337 	ctlr = edev->ctlr;
2338 	qlock(&ctlr->alock);
2339 	if(waserror()){
2340 		//print("ether4330: attach failed: %s\n", up->errstr);
2341 		qunlock(&ctlr->alock);
2342 		nexterror();
2343 	}
2344 	if(ctlr->edev == nil){
2345 		if(ctlr->chipid == 0){
2346 			sdioinit();
2347 			sbinit(ctlr);
2348 		}
2349 		fwload(ctlr);
2350 		sbenable(ctlr);
2351 		kproc("wifireader", rproc, edev);
2352 		kproc("wifitimer", lproc, edev);
2353 		if(ctlr->regufile)
2354 			reguload(ctlr, ctlr->regufile);
2355 		wlinit(edev, ctlr);
2356 		ctlr->edev = edev;
2357 	}
2358 	qunlock(&ctlr->alock);
2359 	poperror();
2360 }
2361 
2362 static void
etherbcmshutdown(Ether *)2363 etherbcmshutdown(Ether*)
2364 {
2365 	sdioreset();
2366 }
2367 
2368 
2369 static int
etherbcmpnp(Ether * edev)2370 etherbcmpnp(Ether* edev)
2371 {
2372 	Ctlr *ctlr;
2373 
2374 	ctlr = malloc(sizeof(Ctlr));
2375 	ctlr->chanid = Wifichan;
2376 	edev->ctlr = ctlr;
2377 	edev->attach = etherbcmattach;
2378 	edev->transmit = etherbcmtransmit;
2379 	edev->ifstat = etherbcmifstat;
2380 	edev->ctl = etherbcmctl;
2381 	edev->scanbs = etherbcmscan;
2382 	edev->shutdown = etherbcmshutdown;
2383 	edev->arg = edev;
2384 
2385 	return 0;
2386 }
2387 
2388 void
ether4330link(void)2389 ether4330link(void)
2390 {
2391 	addethercard("4330", etherbcmpnp);
2392 }
2393