summaryrefslogtreecommitdiff
path: root/sys/dev/ic/if_wi.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ic/if_wi.c')
-rw-r--r--sys/dev/ic/if_wi.c194
1 files changed, 128 insertions, 66 deletions
diff --git a/sys/dev/ic/if_wi.c b/sys/dev/ic/if_wi.c
index 1e729efd582..894aedc589c 100644
--- a/sys/dev/ic/if_wi.c
+++ b/sys/dev/ic/if_wi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_wi.c,v 1.45 2002/04/05 15:35:34 millert Exp $ */
+/* $OpenBSD: if_wi.c,v 1.46 2002/04/06 20:31:56 millert Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
@@ -124,7 +124,7 @@ u_int32_t widebug = WIDEBUG;
#if !defined(lint) && !defined(__OpenBSD__)
static const char rcsid[] =
- "$OpenBSD: if_wi.c,v 1.45 2002/04/05 15:35:34 millert Exp $";
+ "$OpenBSD: if_wi.c,v 1.46 2002/04/06 20:31:56 millert Exp $";
#endif /* lint */
#ifdef foo
@@ -269,14 +269,14 @@ wi_attach(sc, print_cis)
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0);
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
IFM_IEEE80211_ADHOC, 0), 0);
- if (sc->sc_prism2)
+ if (sc->sc_firmware_type == WI_INTERSIL)
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
IFM_IEEE80211_HOSTAP, 0), 0);
if (sc->wi_supprates & WI_SUPPRATES_1M) {
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0);
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
IFM_IEEE80211_ADHOC, 0), 0);
- if (sc->sc_prism2)
+ if (sc->sc_firmware_type == WI_INTERSIL)
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
IFM_IEEE80211_HOSTAP, 0), 0);
}
@@ -284,7 +284,7 @@ wi_attach(sc, print_cis)
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0);
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
IFM_IEEE80211_ADHOC, 0), 0);
- if (sc->sc_prism2)
+ if (sc->sc_firmware_type == WI_INTERSIL)
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
IFM_IEEE80211_HOSTAP, 0), 0);
}
@@ -292,7 +292,7 @@ wi_attach(sc, print_cis)
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0);
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
IFM_IEEE80211_ADHOC, 0), 0);
- if (sc->sc_prism2)
+ if (sc->sc_firmware_type == WI_INTERSIL)
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
IFM_IEEE80211_HOSTAP, 0), 0);
}
@@ -300,7 +300,7 @@ wi_attach(sc, print_cis)
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0);
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
IFM_IEEE80211_ADHOC, 0), 0);
- if (sc->sc_prism2)
+ if (sc->sc_firmware_type == WI_INTERSIL)
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
IFM_IEEE80211_HOSTAP, 0), 0);
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_MANUAL, 0, 0), 0);
@@ -683,10 +683,29 @@ STATIC void
wi_reset(sc)
struct wi_softc *sc;
{
+ u_int8_t cor_value;
+
DPRINTF(WID_RESET, ("wi_reset: sc %p\n", sc));
+ /*
+ * Do a soft reset of the card. This is required by Symbol cards
+ * and shouldn't hurt others. We don't do this on Lucent cards
+ * because it messes up some old Lucent firmware revisions.
+ */
+ if (sc->sc_firmware_type != WI_LUCENT) {
+ cor_value = bus_space_read_2(sc->wi_ltag, sc->wi_lhandle,
+ sc->wi_cor_offset);
+ bus_space_write_1(sc->wi_ltag, sc->wi_lhandle,
+ sc->wi_cor_offset, (cor_value | WI_COR_SOFT_RESET));
+ DELAY(1000);
+ bus_space_write_1(sc->wi_ltag, sc->wi_lhandle,
+ sc->wi_cor_offset, (cor_value & ~WI_COR_SOFT_RESET));
+ DELAY(1000);
+ }
+
if (wi_cmd(sc, WI_CMD_INI, 0))
printf(WI_PRT_FMT ": init failed\n", WI_PRT_ARG(sc));
+
CSR_WRITE_2(sc, WI_INT_EN, 0);
CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
@@ -708,7 +727,7 @@ wi_read_record(sc, ltv)
int len, code;
struct wi_ltv_gen *oltv, p2ltv;
- if (sc->sc_prism2) {
+ if (sc->sc_firmware_type != WI_LUCENT) {
oltv = ltv;
switch (ltv->wi_type) {
case WI_RID_ENCRYPTION:
@@ -752,7 +771,7 @@ wi_read_record(sc, ltv)
if (ltv->wi_len > 1)
CSR_READ_RAW_2(sc, WI_DATA1, ptr, (ltv->wi_len-1)*2);
- if (sc->sc_prism2) {
+ if (sc->sc_firmware_type != WI_LUCENT) {
int v;
switch (oltv->wi_type) {
@@ -778,15 +797,9 @@ wi_read_record(sc, ltv)
oltv->wi_val = htole16(0);
break;
case WI_RID_TX_CRYPT_KEY:
- oltv->wi_len = 2;
- oltv->wi_val = ltv->wi_val;
- break;
case WI_RID_CNFAUTHMODE:
oltv->wi_len = 2;
- if (ltv->wi_val & htole16(0x01))
- oltv->wi_val = htole16(1);
- else if (ltv->wi_val & htole16(0x02))
- oltv->wi_val = htole16(2);
+ oltv->wi_val = ltv->wi_val;
break;
}
}
@@ -806,7 +819,7 @@ wi_write_record(sc, ltv)
int i;
struct wi_ltv_gen p2ltv;
- if (sc->sc_prism2) {
+ if (sc->sc_firmware_type != WI_LUCENT) {
int v;
switch (ltv->wi_type) {
@@ -834,11 +847,14 @@ wi_write_record(sc, ltv)
/* Disable tx encryption...
* it's broken.
*/
- p2ltv.wi_val = htole16(0x13);
+ p2ltv.wi_val = htole16(HOST_ENCRYPT |
+ PRIVACY_INVOKED |
+ EXCLUDE_UNENCRYPTED);
else
- p2ltv.wi_val = htole16(0x03);
+ p2ltv.wi_val = htole16(PRIVACY_INVOKED |
+ EXCLUDE_UNENCRYPTED);
else
- p2ltv.wi_val = htole16(0x90);
+ p2ltv.wi_val = htole16(HOST_ENCRYPT | HOST_DECRYPT);
ltv = &p2ltv;
break;
case WI_RID_TX_CRYPT_KEY:
@@ -867,15 +883,6 @@ wi_write_record(sc, ltv)
}
}
return (0);
- case WI_RID_CNFAUTHMODE:
- p2ltv.wi_type = WI_RID_CNFAUTHMODE;
- p2ltv.wi_len = 2;
- if (ltv->wi_val == htole16(1))
- p2ltv.wi_val = htole16(0x01);
- else if (ltv->wi_val == htole16(2))
- p2ltv.wi_val = htole16(0x02);
- ltv = &p2ltv;
- break;
}
}
@@ -1021,8 +1028,8 @@ wi_alloc_nicmem(sc, len, id)
if (i < 0)
return(ETIMEDOUT);
- CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
*id = CSR_READ_2(sc, WI_ALLOC_FID);
+ CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
if (wi_seek(sc, *id, 0, WI_BAP0))
return(EIO);
@@ -1306,13 +1313,20 @@ wi_ioctl(ifp, command, data)
error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
if (error)
break;
- if (wreq.wi_type == WI_RID_IFACE_STATS) {
- error = EINVAL;
+ error = EINVAL;
+ switch (wreq.wi_type) {
+ case WI_RID_IFACE_STATS:
break;
- } else if (wreq.wi_type == WI_RID_MGMT_XMIT) {
+ case WI_RID_MGMT_XMIT:
error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val,
wreq.wi_len);
- } else {
+ break;
+ case WI_RID_ROAMING_MODE:
+ /* Symbol cards use 0xFC2D for something else. */
+ if (sc->sc_firmware_type == WI_SYMBOL)
+ break;
+ /* FALLTHROUGH */
+ default:
error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
if (!error)
error = wi_setdef(sc, &wreq);
@@ -1431,8 +1445,9 @@ wi_init(sc)
/* Power Managment Max Sleep */
WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep);
- /* Roaming type */
- WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming);
+ /* Set Roaming Mode unless this is a Symbol card. */
+ if (sc->sc_firmware_type != WI_SYMBOL)
+ WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming);
/* Specify the network name */
WI_SETSTR(WI_RID_DESIRED_SSID, sc->wi_net_name);
@@ -1476,15 +1491,17 @@ wi_init(sc)
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);
- if (sc->sc_prism2 && sc->wi_use_wep) {
+ if (sc->sc_firmware_type != WI_LUCENT && sc->wi_use_wep) {
/*
- * For Prism2 Firmware version less than 0.8.2.
+ * HWB3163 EVAL-CARD Firmware version less than 0.8.2.
+ *
* If promiscuous mode is disabled, the Prism2 chip
* does not work with WEP .
* I'm currently investigating the details of this.
* (ichiro@netbsd.org)
*/
- if (sc->sc_prism2_ver < 82 ) {
+ if (sc->sc_firmware_type == WI_INTERSIL &&
+ sc->sc_sta_firmware_ver < 802 ) {
/* firm ver < 0.8.2 */
WI_SETVAL(WI_RID_PROMISC, 1);
}
@@ -1692,9 +1709,10 @@ nextpkt:
if (!wihap_check_tx(&sc->wi_hostap_info, eh->ether_dhost,
&tx_frame.wi_tx_rate) && !(ifp->if_flags & IFF_PROMISC)) {
if (ifp->if_flags & IFF_DEBUG)
- printf("wi_start: dropping unassoc dst %s\n",
+ printf(WI_PRT_FMT
+ ": wi_start: dropping unassoc dst %s\n",
+ WI_PRT_ARG(sc),
ether_sprintf(eh->ether_dhost));
- m_freem(m0);
goto nextpkt;
}
}
@@ -1770,8 +1788,10 @@ nextpkt:
if (sc->wi_ptype == WI_PORTTYPE_AP && sc->wi_use_wep) {
- /* Do host encryption. */
- printf("XXX: host encrypt not implemented for 802.3\n");
+ /* Do host encryption. (XXX - not implemented) */
+ printf(WI_PRT_FMT
+ ": host encrypt not implemented for 802.3\n",
+ WI_PRT_ARG(sc));
} else {
m_copydata(m0, 0, m0->m_pkthdr.len,
(caddr_t)&sc->wi_txbuf);
@@ -1795,7 +1815,7 @@ nextpkt:
m_freem(m0);
if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id))
- printf(WI_PRT_FMT ": xmit failed\n", WI_PRT_ARG(sc));
+ printf(WI_PRT_FMT ": wi_start: xmit failed\n", WI_PRT_ARG(sc));
ifp->if_flags |= IFF_OACTIVE;
@@ -1839,7 +1859,8 @@ wi_mgmt_xmit(sc, data, len)
(len - sizeof(struct wi_80211_hdr)) + 2);
if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id)) {
- printf(WI_PRT_FMT ": xmit failed\n", WI_PRT_ARG(sc));
+ printf(WI_PRT_FMT ": wi_mgmt_xmit: xmit failed\n",
+ WI_PRT_ARG(sc));
return(EIO);
}
@@ -1908,12 +1929,14 @@ wi_get_id(sc, print_cis)
{
struct wi_ltv_ver ver;
struct wi_ltv_cis cis;
+ u_int16_t pri_fw_ver[3];
const char *p;
if (print_cis) {
/*
* For PCI attachments the CIS strings won't have been printed
* so print them here.
+ * XXX - messes up each odd character on Symbol cards
*/
cis.wi_type = WI_RID_CIS;
cis.wi_len = sizeof(cis.wi_cis);
@@ -1938,51 +1961,66 @@ wi_get_id(sc, print_cis)
switch (letoh16(ver.wi_ver[0])) {
case WI_NIC_EVB2:
p = "PRISM I HFA3841(EVB2)";
- sc->sc_prism2 = 1;
+ sc->sc_firmware_type = WI_INTERSIL;
break;
case WI_NIC_HWB3763:
p = "PRISM II HWB3763 rev.B";
- sc->sc_prism2 = 1;
+ sc->sc_firmware_type = WI_INTERSIL;
break;
case WI_NIC_HWB3163:
p = "PRISM II HWB3163 rev.A";
- sc->sc_prism2 = 1;
+ sc->sc_firmware_type = WI_INTERSIL;
break;
case WI_NIC_HWB3163B:
p = "PRISM II HWB3163 rev.B";
- sc->sc_prism2 = 1;
+ sc->sc_firmware_type = WI_INTERSIL;
break;
case WI_NIC_EVB3:
p = "PRISM II HFA3842(EVB3)";
- sc->sc_prism2 = 1;
+ sc->sc_firmware_type = WI_INTERSIL;
break;
case WI_NIC_HWB1153:
p = "PRISM I HFA1153";
- sc->sc_prism2 = 1;
+ sc->sc_firmware_type = WI_INTERSIL;
break;
case WI_NIC_P2_SST:
p = "PRISM II HWB3163 SST-flash";
- sc->sc_prism2 = 1;
+ sc->sc_firmware_type = WI_INTERSIL;
break;
case WI_NIC_PRISM2_5:
p = "PRISM 2.5 ISL3873";
- sc->sc_prism2 = 1;
+ sc->sc_firmware_type = WI_INTERSIL;
break;
case WI_NIC_3874A:
p = "PRISM 2.5 ISL3874A(PCI)";
- sc->sc_prism2 = 1;
+ sc->sc_firmware_type = WI_INTERSIL;
break;
case WI_NIC_37300P:
p = "PRISM 2.5 ISL37300P";
- sc->sc_prism2 = 1;
+ sc->sc_firmware_type = WI_INTERSIL;
break;
default:
- p = "Lucent chip or unknown chip";
- sc->sc_prism2 = 0;
+ if (letoh16(ver.wi_ver[0]) & 0x8000) {
+ p = "Unknown PRISM2 chip";
+ sc->sc_firmware_type = WI_INTERSIL;
+ } else {
+ sc->sc_firmware_type = WI_LUCENT;
+ }
break;
}
- /* get firmware version */
+ /* get primary firmware version (XXX - how to do Lucent?) */
+ if (sc->sc_firmware_type != WI_LUCENT) {
+ bzero(&ver, sizeof(ver));
+ ver.wi_type = WI_RID_PRI_IDENTITY;
+ ver.wi_len = 5;
+ wi_read_record(sc, (struct wi_ltv_gen *)&ver);
+ pri_fw_ver[0] = letoh16(ver.wi_ver[2]);
+ pri_fw_ver[1] = letoh16(ver.wi_ver[3]);
+ pri_fw_ver[2] = letoh16(ver.wi_ver[1]);
+ }
+
+ /* get station firmware version */
bzero(&ver, sizeof(ver));
ver.wi_type = WI_RID_STA_IDENTITY;
ver.wi_len = 5;
@@ -1990,15 +2028,39 @@ wi_get_id(sc, print_cis)
ver.wi_ver[1] = letoh16(ver.wi_ver[1]);
ver.wi_ver[2] = letoh16(ver.wi_ver[2]);
ver.wi_ver[3] = letoh16(ver.wi_ver[3]);
- if (sc->sc_prism2) {
- printf("\n%s: %s, Firmware %d.%d.%d, ",
- WI_PRT_ARG(sc), p, ver.wi_ver[2],
- ver.wi_ver[3], ver.wi_ver[1]);
- sc->sc_prism2_ver = ver.wi_ver[2] * 100 +
- ver.wi_ver[3] * 10 + ver.wi_ver[1];
- } else {
+ sc->sc_sta_firmware_ver = ver.wi_ver[2] * 10000 +
+ ver.wi_ver[3] * 100 + ver.wi_ver[1];
+
+ if (sc->sc_firmware_type == WI_INTERSIL &&
+ (sc->sc_sta_firmware_ver == 10102 || sc->sc_sta_firmware_ver == 20102)) {
+ struct wi_ltv_str sver;
+ char *p;
+
+ bzero(&sver, sizeof(sver));
+ sver.wi_type = WI_RID_SYMBOL_IDENTITY;
+ sver.wi_len = 7;
+ /* value should be "V2.00-11" */
+ if (wi_read_record(sc, (struct wi_ltv_gen *)&sver) == 0 &&
+ *(p = (char *)sver.wi_str) == 'V' &&
+ p[2] == '.' && p[5] == '-' && p[8] == '\0') {
+ sc->sc_firmware_type = WI_SYMBOL;
+ sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 +
+ (p[3] - '0') * 1000 + (p[4] - '0') * 100 +
+ (p[6] - '0') * 10 + (p[7] - '0');
+ }
+ }
+
+ if (sc->sc_firmware_type == WI_LUCENT) {
printf("\n%s: Firmware %d.%d variant %d, ", WI_PRT_ARG(sc),
ver.wi_ver[2], ver.wi_ver[3], ver.wi_ver[1]);
+ } else {
+ printf("\n%s: %s%s, Firmware %d.%d.%d (primary), %d.%d.%d (station), ",
+ WI_PRT_ARG(sc),
+ sc->sc_firmware_type == WI_SYMBOL ? "Symbol " : "", p,
+ pri_fw_ver[0], pri_fw_ver[1], pri_fw_ver[2],
+ sc->sc_sta_firmware_ver / 10000,
+ (sc->sc_sta_firmware_ver % 10000) / 100,
+ sc->sc_sta_firmware_ver % 100);
}
return;
@@ -2069,7 +2131,7 @@ wi_media_change(ifp)
(IFM_IEEE80211_ADHOC|IFM_IEEE80211_HOSTAP))
return (EINVAL);
if ((sc->sc_media.ifm_cur->ifm_media & IFM_IEEE80211_HOSTAP) &&
- !sc->sc_prism2)
+ sc->sc_firmware_type == WI_LUCENT)
return (EINVAL);
if ((sc->sc_media.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC))