Subject: wi0 on SMC 2632W
To: None <port-i386@netbsd.org>
From: Rafal Boni <rafal@mediaone.net>
List: port-i386
Date: 12/18/2000 16:33:03
So, in part because Seebs started playing with the wi driver on cheapo cards
and in part because a co-worker picked up a set of SMC 802.11 cards, I had to
check out and see if things worked with that card.

Taking Seebs' work and some changes from the patches by Bill Paul, I got the
card to the point where I could diff my changes against anoncvs.netbsd.org,
using the Airport that one of my other co-workers has on our network...

Here are the patches I used... All the credit goes to Seebs and Bill for the
hard work, I just attempted to distill a set of patches that would make this
specific card go.

There are still some gotchas:
	(1) Still get timeout on wi_init.
	(2) Get occasional 'wi_read[0xFC80] got X out of Y characters'
		Where X,Y tend to be 4 and 1 or 49 and 16.
	(3) The driver forces PRISMII mode currently, as the card ID's
		itself as a Lucent WaveLan/IEEE card.

These patches also add the correct patches for if_wireg.h (Seebs had the
order reversed).

--rafal

Index: if_wi.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/pcmcia/if_wi.c,v
retrieving revision 1.41
diff -b -u -r1.41 if_wi.c
--- if_wi.c	2000/10/13 19:15:08	1.41
+++ if_wi.c	2000/12/18 21:19:02
@@ -320,6 +320,8 @@
 	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;
@@ -347,8 +349,11 @@
 	if (pp == NULL) {
 		/* should not happen */
 		sc->sc_prism2 = 0;
-	} else
-		sc->sc_prism2 = pp->pp_prism2;
+        } 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);
 
@@ -360,10 +365,23 @@
 	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 = 4;
-	wi_read_record(sc, (struct wi_ltv_gen *)&mac);
+      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);
 
 	/*
@@ -740,7 +758,21 @@
 {
 	int			i, s = 0;
 
+	/* wait for the busy bit to clear */
+	for (i = 0; i < WI_TIMEOUT; i++) {
+		if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY)) {
+			break;
+		}
+		DELAY(10*1000);	/* 10 m sec */
+	}
+
+	if (i == WI_TIMEOUT) {
+		return(ETIMEDOUT);
+	}
+
 	CSR_WRITE_2(sc, WI_PARAM0, val);
+	CSR_WRITE_2(sc, WI_PARAM1, 0);
+	CSR_WRITE_2(sc, WI_PARAM2, 0);
 	CSR_WRITE_2(sc, WI_COMMAND, cmd);
 
 	for (i = 0; i < WI_TIMEOUT; i++) {
@@ -772,8 +804,10 @@
 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);
+        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);
 
@@ -811,12 +845,16 @@
 	}
 
 	/* Tell the NIC to enter record read mode. */
-	if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type))
+	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))
+	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
@@ -824,11 +862,17 @@
 	 * room to hold all of the returned data).
 	 */
 	len = CSR_READ_2(sc, WI_DATA1);
-	if (len > ltv->wi_len)
+	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)
+	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;
@@ -925,6 +969,7 @@
 				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;
 			}
@@ -1116,6 +1161,8 @@
 		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;
 	}
 
@@ -1138,6 +1185,7 @@
 	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
@@ -1367,9 +1415,12 @@
 			error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val,
 			    wreq.wi_len);
 		} else {
-			if (sc->sc_enabled != 0)
+                      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)
@@ -1494,6 +1545,7 @@
 	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) {
@@ -1502,6 +1554,7 @@
 		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. */
@@ -1808,10 +1861,14 @@
 	struct wi_req *wreq;
 	struct ieee80211_nwid *ws;
 {
+      int ret;
 
 	wreq->wi_type = type;
 	wi_request_fill_ssid(wreq, ws);
-	return (wi_write_record(sc, (struct wi_ltv_gen *)wreq));
+      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
@@ -1950,6 +2007,7 @@
 	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;
 	}
@@ -1962,6 +2020,7 @@
 	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;
 	}
@@ -1973,6 +2032,7 @@
 	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;
 	}
Index: if_wireg.h
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/pcmcia/if_wireg.h,v
retrieving revision 1.6
diff -b -u -r1.6 if_wireg.h
--- if_wireg.h	2000/05/23 08:41:49	1.6
+++ if_wireg.h	2000/12/18 21:19:06
@@ -296,6 +296,7 @@
 		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)					\
@@ -415,6 +416,12 @@
 	u_int16_t		wi_len;
 	u_int16_t		wi_type;
 	u_int8_t		wi_mac_addr[6];
+};
+
+struct wi_ltv_serial    {
+	u_int16_t		wi_len;
+	u_int16_t		wi_type;
+	u_int8_t		wi_serial[12];
 };
 
 /*

----
Rafal Boni                                                   rafal@mediaone.net