Subject: Okay, time for some real help. wi0 works!
To: None <port-i386@netbsd.org>
From: Peter Seebach <seebs@plethora.net>
List: port-i386
Date: 12/18/2000 01:03:53
The good news:  IT WORKS!  I HAVE EXCHANGED PACKETS WITH MY MAC!

The bad news:  I have absolutely *NO* idea how I fixed it.

init still fails (it times out).

I enclose the diffs.  There are a couple of diffs for if_wireg.h - but I
forgot to make a .orig of it, so they may be slightly wrong.

Anyway, at this point, I would love it if other people with similar cards
could find out:

1.  Whether these diffs work with any cards other than the Linksys.
2.  Whether these diffs make any sense.

I really don't understand this.  BTW, for the curious, the Linksys WPC11
thinks it's a "Wavelan/IEEE" card, so it shows up as a Prism I, but it
may actually be a Prism II, according to reviews.  I had to hand-set it
to prism2.  Or maybe I didn't; that alone didn't fix it, but doing that
*and everything else* seems to have done it.

Apparently, the big thing is that every command sent *must be followed by
a check of the status regs*.  I guess.

I would like to take this opportunity to declare the sheer depth of admiration
I have for those of you who do kernel hacking regularly.  I am amazed that you
can make progress on this stuff, it seems quite strange to me.

If anyone wants to help get this code cleaned up, I'm open to running test
code on my system, as long as the worst that can happen is "oops, no packets".

*** if_wireg.h.orig	Mon Dec 18 00:52:10 2000
--- if_wireg.h	Mon Dec 18 00:52:35 2000
***************
*** 296,302 ****
  		g.wi_type = recno;		\
  		g.wi_val = val;			\
  		wi_write_record(sc, &g);	\
- 		wi_read_record(sc, &g);	\
  	} while (0)
  
  #define WI_SETSTR(recno, str)					\
--- 296,301 ----
***************
*** 416,427 ****
  	u_int16_t		wi_len;
  	u_int16_t		wi_type;
  	u_int8_t		wi_mac_addr[7];
- };
- 
- struct wi_ltv_serial {
- 	u_int16_t		wi_len;
- 	u_int16_t		wi_type;
- 	u_int8_t		wi_serial[12];
  };
  
  /*
--- 415,420 ----

*** if_wi.c.orig	Sun Dec 17 19:17:06 2000
--- if_wi.c	Mon Dec 18 00:47:16 2000
***************
*** 309,314 ****
--- 309,316 ----
  	static const u_int8_t empty_macaddr[ETHER_ADDR_LEN] = {
  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  	};
+ 	int i;
+ 	struct wi_ltv_serial	serialno;
  
  	/* Enable the card. */
  	sc->sc_pf = pa->pf;
***************
*** 336,343 ****
  	if (pp == NULL) {
  		/* should not happen */
  		sc->sc_prism2 = 0;
! 	} else
! 		sc->sc_prism2 = pp->pp_prism2;
  
  	callout_init(&sc->wi_inquire_ch);
  
--- 338,348 ----
  	if (pp == NULL) {
  		/* should not happen */
  		sc->sc_prism2 = 0;
! 	} else {
! 		printf("card is '%s'?\n", pp->pp_name ? pp->pp_name : "(null)");
! 		/* sc->sc_prism2 = pp->pp_prism2; */
! 		sc->sc_prism2 = 1;
! 	}
  
  	callout_init(&sc->wi_inquire_ch);
  
***************
*** 349,358 ****
  	wi_reset(sc);
  
  	memset(&mac, 0, sizeof(mac));
  	/* Read the station address. */
  	mac.wi_type = WI_RID_MAC_NODE;
! 	mac.wi_len = 4;
! 	wi_read_record(sc, (struct wi_ltv_gen *)&mac);
  	memcpy(sc->sc_macaddr, mac.wi_mac_addr, ETHER_ADDR_LEN);
  
  	/*
--- 354,376 ----
  	wi_reset(sc);
  
  	memset(&mac, 0, sizeof(mac));
+ 	serialno.wi_type = WI_RID_SERIALNO;
+ 	serialno.wi_len = 12;
+ 	i = wi_read_record(sc, (struct wi_ltv_gen *)&serialno);
+ 	if (i) {
+ 		printf("read serial failed errno %d\n", i);
+ 	} else
+ 		for (i = 0; i < 12; ++i) {
+ 			printf("sn byte 0x%x: %02x\n", i, serialno.wi_serial[i]);
+ 		}
+ 
  	/* Read the station address. */
  	mac.wi_type = WI_RID_MAC_NODE;
! 	mac.wi_len = 7;
! 	i = wi_read_record(sc, (struct wi_ltv_gen *)&mac);
! 	if (i) {
! 		printf("read mac failed errno %d\n", i);
! 	}
  	memcpy(sc->sc_macaddr, mac.wi_mac_addr, ETHER_ADDR_LEN);
  
  	/*
***************
*** 727,732 ****
--- 745,763 ----
  {
  	int			i, s = 0;
  
+ 	for (i = 0; i < WI_TIMEOUT; ++i) {
+ 		s = CSR_READ_2(sc, WI_COMMAND);
+ 		if (!(s & WI_CMD_BUSY)) {
+ 			break;
+ 		} else if (i == 0) {
+ 			s = CSR_READ_2(sc, WI_STATUS);
+ 			CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
+ 		}
+ 	}
+ 	if (i == WI_TIMEOUT) {
+ 		printf("always busy!\n");
+ 		return (ETIMEDOUT);
+ 	}
  	CSR_WRITE_2(sc, WI_PARAM0, val);
  	CSR_WRITE_2(sc, WI_COMMAND, cmd);
  
***************
*** 759,766 ****
  static void wi_reset(sc)
  	struct wi_softc		*sc;
  {
! 	if (wi_cmd(sc, WI_CMD_INI, 0))
! 		printf("%s: init failed\n", sc->sc_dev.dv_xname);
  	CSR_WRITE_2(sc, WI_INT_EN, 0);
  	CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
  
--- 790,799 ----
  static void wi_reset(sc)
  	struct wi_softc		*sc;
  {
! 	int i;
! 
! 	if ((i = wi_cmd(sc, WI_CMD_INI, 0)))
! 		printf("%s: init failed [errno %d]\n", sc->sc_dev.dv_xname, i);
  	CSR_WRITE_2(sc, WI_INT_EN, 0);
  	CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
  
***************
*** 816,827 ****
  	}
  
  	/* Tell the NIC to enter record read mode. */
! 	if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type))
  		return(EIO);
  
  	/* Seek to the record. */
! 	if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1))
  		return(EIO);
  
  	/*
  	 * Read the length and record type and make sure they
--- 849,864 ----
  	}
  
  	/* Tell the NIC to enter record read mode. */
! 	if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type)) {
! 		printf("couldn't access record of type 0x%X\n", ltv->wi_type);
  		return(EIO);
+ 	}
  
  	/* Seek to the record. */
! 	if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1)) {
! 		printf("couldn't seek record of type 0x%X\n", ltv->wi_type);
  		return(EIO);
+ 	}
  
  	/*
  	 * Read the length and record type and make sure they
***************
*** 829,839 ****
  	 * room to hold all of the returned data).
  	 */
  	len = CSR_READ_2(sc, WI_DATA1);
! 	if (len > ltv->wi_len)
  		return(ENOSPC);
  	code = CSR_READ_2(sc, WI_DATA1);
! 	if (code != ltv->wi_type)
  		return(EIO);
  
  	ltv->wi_len = len;
  	ltv->wi_type = code;
--- 866,882 ----
  	 * room to hold all of the returned data).
  	 */
  	len = CSR_READ_2(sc, WI_DATA1);
! 	if (len > ltv->wi_len) {
! 		printf("wi_read [0x%X] got %d out of %d characters!\n",
! 			ltv->wi_type, len, ltv->wi_len);
  		return(ENOSPC);
+ 	}
  	code = CSR_READ_2(sc, WI_DATA1);
! 	if (code != ltv->wi_type) {
! 		printf("wi_read got type %X, expecting %X\n",
! 			code, ltv->wi_type);
  		return(EIO);
+ 	}
  
  	ltv->wi_len = len;
  	ltv->wi_type = code;
***************
*** 902,907 ****
--- 945,951 ----
  				ws.wi_str[5] = '\0';
  				error = wi_write_record(sc,
  				    (struct wi_ltv_gen *)&ws);
+ 				wi_read_record(sc, (struct wi_ltv_gen *) &ws);
  				if (error)
  					return error;
  			}
***************
*** 1093,1098 ****
--- 1137,1144 ----
  		mcast.wi_len = ((ETHER_ADDR_LEN / 2) * 16) + 1;
  
  		wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
+ 		mcast.wi_len = 16;
+ 		wi_read_record(sc, (struct wi_ltv_gen *)&mcast);
  		return;
  	}
  
***************
*** 1119,1124 ****
--- 1165,1171 ----
  	mcast.wi_type = WI_RID_MCAST;
  	mcast.wi_len = ((ETHER_ADDR_LEN / 2) * i) + 1;
  	wi_write_record(sc, (struct wi_ltv_gen *)&mcast);
+ 	wi_read_record(sc, (struct wi_ltv_gen *)&mcast);
  }
  
  static int
***************
*** 1269,1275 ****
  		error = EIO;
  #else
  #ifdef DIAGNOSTIC
! 		printf("%s: wi_getdef: unknown request %d\n",
  		    sc->sc_dev.dv_xname, wreq->wi_type);
  #endif
  #endif
--- 1316,1322 ----
  		error = EIO;
  #else
  #ifdef DIAGNOSTIC
! 		printf("%s: wi_getdef: unknown request 0x%X\n",
  		    sc->sc_dev.dv_xname, wreq->wi_type);
  #endif
  #endif
***************
*** 1420,1428 ****
  			error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val,
  			    wreq.wi_len);
  		} else {
! 			if (sc->sc_enabled != 0)
  				error = wi_write_record(sc,
  				    (struct wi_ltv_gen *)&wreq);
  			if (error == 0)
  				error = wi_setdef(sc, &wreq);
  			if (error == 0 && sc->sc_enabled != 0)
--- 1467,1478 ----
  			error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val,
  			    wreq.wi_len);
  		} else {
! 			if (sc->sc_enabled != 0) {
  				error = wi_write_record(sc,
  				    (struct wi_ltv_gen *)&wreq);
+ 				wi_read_record(sc,
+ 				    (struct wi_ltv_gen *)&wreq);
+ 			}
  			if (error == 0)
  				error = wi_setdef(sc, &wreq);
  			if (error == 0 && sc->sc_enabled != 0)
***************
*** 1536,1541 ****
--- 1586,1592 ----
  	mac.wi_type = WI_RID_MAC_NODE;
  	memcpy(&mac.wi_mac_addr, sc->sc_macaddr, ETHER_ADDR_LEN);
  	wi_write_record(sc, (struct wi_ltv_gen *)&mac);
+ 	wi_read_record(sc, (struct wi_ltv_gen *)&mac);
  
  	/* Configure WEP. */
  	if (sc->wi_has_wep) {
***************
*** 1544,1549 ****
--- 1595,1601 ----
  		sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
  		sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
  		wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys);
+ 		wi_read_record(sc, (struct wi_ltv_gen *)&sc->wi_keys);
  	}
  
  	/* Initialize promisc mode. */
***************
*** 1834,1843 ****
  	struct wi_req *wreq;
  	struct ieee80211_nwid *ws;
  {
  
  	wreq->wi_type = type;
  	wi_request_fill_ssid(wreq, ws);
! 	return (wi_write_record(sc, (struct wi_ltv_gen *)wreq));
  }
  
  static int
--- 1886,1899 ----
  	struct wi_req *wreq;
  	struct ieee80211_nwid *ws;
  {
+ 	int ret;
  
  	wreq->wi_type = type;
  	wi_request_fill_ssid(wreq, ws);
! 	ret = wi_write_record(sc, (struct wi_ltv_gen *)wreq);
! 	wreq->wi_len = 20;
! 	wi_read_record(sc, (struct wi_ltv_gen *)wreq);
! 	return ret;
  }
  
  static int
***************
*** 1976,1981 ****
--- 2032,2038 ----
  	wk->wi_type = WI_RID_DEFLT_CRYPT_KEYS;
  	if (sc->sc_enabled != 0) {
  		error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
+ 		wi_read_record(sc, (struct wi_ltv_gen *)&wreq);
  		if (error)
  			return error;
  	}
***************
*** 1988,1993 ****
--- 2045,2051 ----
  	wreq.wi_val[0] = nwkey->i_defkid - 1;
  	if (sc->sc_enabled != 0) {
  		error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
+ 		wi_read_record(sc, (struct wi_ltv_gen *)&wreq);
  		if (error)
  			return error;
  	}
***************
*** 1999,2004 ****
--- 2057,2063 ----
  	wreq.wi_val[0] = nwkey->i_wepon;
  	if (sc->sc_enabled != 0) {
  		error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
+ 		wi_read_record(sc, (struct wi_ltv_gen *)&wreq);
  		if (error)
  			return error;
  	}