📄 if_wi.c
字号:
CSR_WRITE_2(sc, WI_PARAM2, val2); CSR_WRITE_2(sc, WI_COMMAND, cmd); for (i = 0; i < WI_TIMEOUT; i++) { /* * Wait for 'command complete' bit to be * set in the event status register. */ s = CSR_READ_2(sc, WI_EVENT_STAT); if (s & WI_EV_CMD) { /* Ack the event and read result code. */ s = CSR_READ_2(sc, WI_STATUS); CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);#ifdef foo if ((s & WI_CMD_CODE_MASK) != (cmd & WI_CMD_CODE_MASK)) return(EIO);#endif if (s & WI_STAT_CMD_RESULT) { count--; return(EIO); } break; } DELAY(WI_DELAY); } count--; if (i == WI_TIMEOUT) { device_printf(sc->dev, "timeout in wi_cmd 0x%04x; event status 0x%04x\n", cmd, s); return(ETIMEDOUT); } return(0);}static voidwi_reset(sc) struct wi_softc *sc;{#define WI_INIT_TRIES 3 int i; int tries; /* Symbol firmware cannot be initialized more than once */ if (sc->sc_firmware_type == WI_SYMBOL && sc->sc_enabled) return; if (sc->sc_firmware_type == WI_SYMBOL) tries = 1; else tries = WI_INIT_TRIES; for (i = 0; i < tries; i++) { if (wi_cmd(sc, WI_CMD_INI, 0, 0, 0) == 0) break; DELAY(WI_DELAY * 1000); } sc->sc_enabled = 1; if (i == tries) { device_printf(sc->dev, "init failed\n"); return; } CSR_WRITE_2(sc, WI_INT_EN, 0); CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); /* Calibrate timer. */ WI_SETVAL(WI_RID_TICK_TIME, 8); return;}/* * Read an LTV record from the NIC. */static intwi_read_record(sc, ltv) struct wi_softc *sc; struct wi_ltv_gen *ltv;{ u_int16_t *ptr; int i, len, code; struct wi_ltv_gen *oltv, p2ltv; oltv = ltv; if (sc->sc_firmware_type != WI_LUCENT) { switch (ltv->wi_type) { case WI_RID_ENCRYPTION: p2ltv.wi_type = WI_RID_P2_ENCRYPTION; p2ltv.wi_len = 2; ltv = &p2ltv; break; case WI_RID_TX_CRYPT_KEY: p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY; p2ltv.wi_len = 2; ltv = &p2ltv; break; case WI_RID_ROAMING_MODE: if (sc->sc_firmware_type == WI_INTERSIL) break; /* not supported */ ltv->wi_len = 1; return 0; case WI_RID_MICROWAVE_OVEN: /* not supported */ ltv->wi_len = 1; return 0; } } /* Tell the NIC to enter record read mode. */ if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type, 0, 0)) 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 * match what we expect (this verifies that we have enough * 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; /* Now read the data. */ ptr = <v->wi_val; for (i = 0; i < ltv->wi_len - 1; i++) ptr[i] = CSR_READ_2(sc, WI_DATA1); if (ltv->wi_type == WI_RID_PORTTYPE && sc->wi_ptype == WI_PORTTYPE_IBSS && ltv->wi_val == sc->wi_ibss_port) { /* * Convert vendor IBSS port type to WI_PORTTYPE_IBSS. * Since Lucent uses port type 1 for BSS *and* IBSS we * have to rely on wi_ptype to distinguish this for us. */ ltv->wi_val = htole16(WI_PORTTYPE_IBSS); } else if (sc->sc_firmware_type != WI_LUCENT) { switch (oltv->wi_type) { case WI_RID_TX_RATE: case WI_RID_CUR_TX_RATE: switch (ltv->wi_val) { case 1: oltv->wi_val = 1; break; case 2: oltv->wi_val = 2; break; case 3: oltv->wi_val = 6; break; case 4: oltv->wi_val = 5; break; case 7: oltv->wi_val = 7; break; case 8: oltv->wi_val = 11; break; case 15: oltv->wi_val = 3; break; default: oltv->wi_val = 0x100 + ltv->wi_val; break; } break; case WI_RID_ENCRYPTION: oltv->wi_len = 2; if (ltv->wi_val & 0x01) oltv->wi_val = 1; else oltv->wi_val = 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 (le16toh(ltv->wi_val) & 0x01) oltv->wi_val = htole16(1); else if (le16toh(ltv->wi_val) & 0x02) oltv->wi_val = htole16(2); break; } } return(0);}/* * Same as read, except we inject data instead of reading it. */static intwi_write_record(sc, ltv) struct wi_softc *sc; struct wi_ltv_gen *ltv;{ uint16_t *ptr; uint16_t val; int i; struct wi_ltv_gen p2ltv; if (ltv->wi_type == WI_RID_PORTTYPE && le16toh(ltv->wi_val) == WI_PORTTYPE_IBSS) { /* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */ p2ltv.wi_type = WI_RID_PORTTYPE; p2ltv.wi_len = 2; p2ltv.wi_val = sc->wi_ibss_port; ltv = &p2ltv; } else if (sc->sc_firmware_type != WI_LUCENT) { switch (ltv->wi_type) { case WI_RID_TX_RATE: p2ltv.wi_type = WI_RID_TX_RATE; p2ltv.wi_len = 2; switch (ltv->wi_val) { case 1: p2ltv.wi_val = 1; break; case 2: p2ltv.wi_val = 2; break; case 3: p2ltv.wi_val = 15; break; case 5: p2ltv.wi_val = 4; break; case 6: p2ltv.wi_val = 3; break; case 7: p2ltv.wi_val = 7; break; case 11: p2ltv.wi_val = 8; break; default: return EINVAL; } p2ltv.wi_val = htole16(p2ltv.wi_val); ltv = &p2ltv; break; case WI_RID_ENCRYPTION: p2ltv.wi_type = WI_RID_P2_ENCRYPTION; p2ltv.wi_len = 2; if (ltv->wi_val & htole16(0x01)) { val = PRIVACY_INVOKED; /* * If using shared key WEP we must set the * EXCLUDE_UNENCRYPTED bit. Symbol cards * need this bit set even when not using * shared key. We can't just test for * IEEE80211_AUTH_SHARED since Symbol cards * have 2 shared key modes. */ if (sc->wi_authtype != IEEE80211_AUTH_OPEN || sc->sc_firmware_type == WI_SYMBOL) val |= EXCLUDE_UNENCRYPTED; /* TX encryption is broken in Host AP mode. */ if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) val |= HOST_ENCRYPT; } else val = HOST_ENCRYPT | HOST_DECRYPT; p2ltv.wi_val = htole16(val); ltv = &p2ltv; break; case WI_RID_TX_CRYPT_KEY: if (ltv->wi_val > WI_NLTV_KEYS) return (EINVAL); p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY; p2ltv.wi_len = 2; p2ltv.wi_val = ltv->wi_val; ltv = &p2ltv; break; case WI_RID_DEFLT_CRYPT_KEYS: { int error; int keylen; struct wi_ltv_str ws; struct wi_ltv_keys *wk = (struct wi_ltv_keys *)ltv; keylen = wk->wi_keys[sc->wi_tx_key].wi_keylen; for (i = 0; i < 4; i++) { bzero(&ws, sizeof(ws)); ws.wi_len = (keylen > 5) ? 8 : 4; ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i; memcpy(ws.wi_str, &wk->wi_keys[i].wi_keydat, keylen); error = wi_write_record(sc, (struct wi_ltv_gen *)&ws); if (error) return error; } return 0; } case WI_RID_CNFAUTHMODE: p2ltv.wi_type = WI_RID_CNFAUTHMODE; p2ltv.wi_len = 2; if (le16toh(ltv->wi_val) == 1) p2ltv.wi_val = htole16(0x01); else if (le16toh(ltv->wi_val) == 2) p2ltv.wi_val = htole16(0x02); ltv = &p2ltv; break; case WI_RID_ROAMING_MODE: if (sc->sc_firmware_type == WI_INTERSIL) break; /* not supported */ return 0; case WI_RID_MICROWAVE_OVEN: /* not supported */ return 0; } } else { /* LUCENT */ switch (ltv->wi_type) { case WI_RID_TX_RATE: switch (ltv->wi_val) { case 1: ltv->wi_val = 1; break; /* 1Mb/s fixed */ case 2: ltv->wi_val = 2; break; /* 2Mb/s fixed */ case 3: ltv->wi_val = 3; break; /* 11Mb/s auto */ case 5: ltv->wi_val = 4; break; /* 5.5Mb/s fixed */ case 6: ltv->wi_val = 6; break; /* 2Mb/s auto */ case 7: ltv->wi_val = 7; break; /* 5.5Mb/s auto */ case 11: ltv->wi_val = 5; break; /* 11Mb/s fixed */ default: return EINVAL; } case WI_RID_TX_CRYPT_KEY: if (ltv->wi_val > WI_NLTV_KEYS) return (EINVAL); break; } } if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1)) return(EIO); CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len); CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type); ptr = <v->wi_val; for (i = 0; i < ltv->wi_len - 1; i++) CSR_WRITE_2(sc, WI_DATA1, ptr[i]); if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type, 0, 0)) return(EIO); return(0);}static intwi_seek(sc, id, off, chan) struct wi_softc *sc; int id, off, chan;{ int i; int selreg, offreg; int status; switch (chan) { case WI_BAP0: selreg = WI_SEL0; offreg = WI_OFF0; break; case WI_BAP1: selreg = WI_SEL1; offreg = WI_OFF1; break; default: device_printf(sc->dev, "invalid data path: %x\n", chan); return(EIO); } CSR_WRITE_2(sc, selreg, id); CSR_WRITE_2(sc, offreg, off); for (i = 0; i < WI_TIMEOUT; i++) { status = CSR_READ_2(sc, offreg); if (!(status & (WI_OFF_BUSY|WI_OFF_ERR))) break; DELAY(WI_DELAY); } if (i == WI_TIMEOUT) { device_printf(sc->dev, "timeout in wi_seek to %x/%x; last status %x\n", id, off, status); return(ETIMEDOUT); } return(0);}static intwi_read_data(sc, id, off, buf, len) struct wi_softc *sc; int id, off; caddr_t buf; int len;{ int i; u_int16_t *ptr; if (wi_seek(sc, id, off, WI_BAP1)) return(EIO); ptr = (u_int16_t *)buf; for (i = 0; i < len / 2; i++) ptr[i] = CSR_READ_2(sc, WI_DATA1); return(0);}/* * According to the comments in the HCF Light code, there is a bug in * the Hermes (or possibly in certain Hermes firmware revisions) where * the chip's internal autoincrement counter gets thrown off during * data writes: the autoincrement is missed, causing one data word to * be overwritten and subsequent words to be written to the wrong memory * locations. The end result is that we could end up transmitting bogus * frames without realizing it. The workaround for this is to write a * couple of extra guard words after the end of the transfer, then * attempt to read then back. If we fail to locate the guard words where * we expect them, we preform the transfer over again. */static intwi_write_data(sc, id, off, buf, len) struct wi_softc *sc; int id, off; caddr_t buf; int len;{ int i; u_int16_t *ptr;#ifdef WI_HERMES_AUTOINC_WAR int retries; retries = 512;again:#endif#ifdef WICACHE/* if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) { device_printf(sc->dev, "off=%d, len=%d\t", off, len); }*/ long msglen; if (off == 0) { struct wi_frame *tx_frame = (struct wi_frame *) buf;/* printf("addr1 = %6D addr2 = %6D addr3 = %6D\n", tx_frame->wi_addr1, ":", tx_frame->wi_addr2, ":", tx_frame->wi_addr3, ":"); printf("addrd = %6D addrs = %6D\n", tx_frame->wi_dst_addr, ":", tx_frame->wi_src_addr, ":");*/ char wrongaddr1[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -