📄 wlandrv.c
字号:
CSR_WRITE_2(sc, WI_SEL0, id); CSR_WRITE_2(sc, WI_OFF0, off); for (i = 0;; i++) { status = CSR_READ_2(sc, WI_OFF0); if ((status & WI_OFF_BUSY) == 0) { break; } if (i == WI_TIMEOUT) { Debug(("timeout in wi_seek to %x/%x\n", id, off)); sc->sc_bap_off = WI_OFF_ERR; /* invalidate */ if (status == 0xffff) { sc->wi_gone = 1; } return ETIMEDOUT; } DELAY(1); } if (status & WI_OFF_ERR) { Debug(("failed in wi_seek to %x/%x\n", id, off)); sc->sc_bap_off = WI_OFF_ERR; /* invalidate */ return EIO; } sc->sc_bap_id = id; sc->sc_bap_off = off; return 0;}/************************************************************//* wi_read_bap *//************************************************************/static int wi_read_bap(struct wi_softc *sc, int id, int off, void *buf, int buflen){ u_int16_t *ptr; int i, error, cnt; if (buflen == 0) { return 0; } if (id != sc->sc_bap_id || off != sc->sc_bap_off) { if ((error = wi_seek_bap(sc, id, off)) != 0) { return error; } } cnt = (buflen + 1) / 2; ptr = (u_int16_t *) buf; for (i = 0; i < cnt; i++) { *ptr++ = CSR_READ_2(sc, WI_DATA0); } sc->sc_bap_off += cnt * 2; return 0;}/************************************************************//* wi_write_bap *//************************************************************/static int wi_write_bap(struct wi_softc *sc, int id, int off, void *buf, int buflen){ u_int16_t *ptr; int i, error, cnt; if (buflen == 0) { return 0; }#ifdef WI_HERMES_AUTOINC_WAR again:#endif if (id != sc->sc_bap_id || off != sc->sc_bap_off) { if ((error = wi_seek_bap(sc, id, off)) != 0) { return error; } } cnt = (buflen + 1) / 2; ptr = (u_int16_t *) buf; for (i = 0; i < cnt; i++) { CSR_WRITE_2(sc, WI_DATA0, ptr[i]); } sc->sc_bap_off += cnt * 2;#ifdef WI_HERMES_AUTOINC_WAR /* * 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. */ if ((sc->sc_flags & WI_FLAGS_BUG_AUTOINC) && (id & 0xf000) == 0) { CSR_WRITE_2(sc, WI_DATA0, 0x1234); CSR_WRITE_2(sc, WI_DATA0, 0x5678); wi_seek_bap(sc, id, sc->sc_bap_off); sc->sc_bap_off = WI_OFF_ERR; /* invalidate */ if (CSR_READ_2(sc, WI_DATA0) != 0x1234 || CSR_READ_2(sc, WI_DATA0) != 0x5678) { Debug(("detect auto increment bug, try again\n")); goto again; } }#endif return 0;}/************************************************************//* wi_read_rid *//************************************************************/static int wi_read_rid(struct wi_softc *sc, int rid, void *buf, int *buflenp){ int error, len; u_int16_t ltbuf[2]; /* * Tell the NIC to enter record read mode. */ error = wi_cmd(sc, WI_CMD_ACCESS | WI_ACCESS_READ, rid, 0, 0); if (error) { return error; } error = wi_read_bap(sc, rid, 0, ltbuf, sizeof(ltbuf)); if (error) { return error; } if (le16toh(ltbuf[1]) != (u_int16_t) rid) { Debug(("record read mismatch, rid=%x, got=%x\n", rid, le16toh(ltbuf[1]))); return EIO; } len = (le16toh(ltbuf[0]) - 1) * 2; /* already got rid */ if (*buflenp < len) { Debug(("record buffer is too small, rid=%x, size=%d, len=%d\n", rid, *buflenp, len)); return ENOSPC; } *buflenp = len; return wi_read_bap(sc, rid, sizeof(ltbuf), buf, len);}/************************************************************//* wi_write_rid *//* *//* Write a block of data to the Resource Identifier. *//* *//* Return: OK or Error cause. *//************************************************************/static int wi_write_rid(struct wi_softc *sc, int rid, void *buf, int buflen){ int error; u_int16_t ltbuf[2]; ltbuf[0] = htole16((buflen + 1) / 2 + 1); /* includes rid */ ltbuf[1] = htole16(rid); error = wi_write_bap(sc, rid, 0, ltbuf, sizeof(ltbuf)); if (error) { return error; } error = wi_write_bap(sc, rid, sizeof(ltbuf), buf, buflen); if (error) { return error; } return wi_cmd(sc, WI_CMD_ACCESS | WI_ACCESS_WRITE, rid, 0, 0);}/************************************************************//* wi_write_val *//* *//* Write the value to the Resource Identifier. *//* The function will write only a WORD *//* *//* Return: OK or Error cause. *//************************************************************/static int wi_write_val(struct wi_softc *sc, int rid, u_int16_t val){ val = htole16(val); return wi_write_rid(sc, rid, &val, sizeof(val));}/************************************************************//* wi_write_txrate *//************************************************************/static int wi_write_txrate(struct wi_softc *sc){ struct ieee80211com *ic = &sc->sc_ic; int i; u_int16_t rate; if (ic->ic_fixed_rate < 0) { rate = 0; /* auto */ } else { rate = (ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL) / 2; } /* * rate: 0, 1, 2, 5, 11 */ switch (sc->sc_firmware_type) { case WI_LUCENT: switch (rate) { case 0: /* auto == 11mbps auto */ rate = 3; break; /* * case 1, 2 map to 1, 2 */ case 5: /* 5.5Mbps -> 4 */ rate = 4; break; case 11: /* 11mbps -> 5 */ rate = 5; break; default: break; } break; default: /* * Choose a bit according to this table. * * * * bit | data rate * * ----+------------------- * * 0 | 1Mbps * * 1 | 2Mbps * * 2 | 5.5Mbps * * 3 | 11Mbps */ for (i = 8; i > 0; i >>= 1) { if ((int) rate >= i) { break; } } if (i == 0) { rate = 0xf; /* auto */ } else { rate = i; } break; } return wi_write_val(sc, WI_RID_TX_RATE, rate);}/************************************************************//* wi_reset *//************************************************************/static int wi_reset(struct wi_softc *sc){ //struct ieee80211com *ic = &sc->sc_ic; /* Harald: Not used */ int i; int error = 0; int tries; /* * Symbol firmware cannot be initialized more than once */ if (sc->sc_firmware_type == WI_SYMBOL && sc->sc_reset) { return (0); } if (sc->sc_firmware_type == WI_SYMBOL) { tries = 1; } else { tries = 3; } for (i = 0; i < tries; i++) { if ((error = wi_cmd(sc, WI_CMD_INI, 0, 0, 0)) == 0) { break; } DELAY(WI_DELAY * 1000); } sc->sc_reset = 1; if (i == tries) { Debug(("init failed\n")); return (error); } CSR_WRITE_2(sc, WI_INT_EN, 0); CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); /* * Calibrate timer */ wi_write_val(sc, WI_RID_TICK_TIME, 8); return (0);}/************************************************************//* WLANInterrupt *//************************************************************/static void WLANInterrupt(void *p){ NUTDEVICE *dev = (NUTDEVICE *) p; struct wi_softc *sc = (struct wi_softc *) dev->dev_dcb; if ((sc->wi_gone == 1) || (sc->sc_enabled == 0)) { CSR_WRITE_2(sc, WI_INT_EN, 0); CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); return; } /* * Disable interrupts. We will enable the interrupt * later in the RxThread. */ CSR_WRITE_2(sc, WI_INT_EN, 0); sc->EventStatus = CSR_READ_2(sc, WI_EVENT_STAT); NutEventPostFromIrq(&sc->InterruptEvent);}/************************************************************//* wi_tx_intr *//************************************************************/static void wi_tx_intr(struct wi_softc *sc){ // struct ieee80211com *ic = &sc->sc_ic; /* Harald: Not used. */ int fid, cur; if (sc->wi_gone) { return; } fid = CSR_READ_2(sc, WI_ALLOC_FID); CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); cur = sc->sc_txcur; if (sc->sc_txd[cur].d_fid != fid) {#if (WLAN_ENABLE_TX_FRAME_DUMP >= 1) Debug(("bad alloc %x != %x, cur %d nxt %d\n", fid, sc->sc_txd[cur].d_fid, cur, sc->sc_txnext));#endif return; } sc->sc_tx_timer = 0; sc->sc_txd[cur].d_len = 0; sc->sc_txcur = cur = (cur + 1) % sc->sc_ntxbuf; if (sc->sc_txd[cur].d_len == 0) { //ifp->if_flags &= ~IFF_OACTIVE; } else { if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, sc->sc_txd[cur].d_fid, 0, 0)) { Debug(("xmit failed\n")); sc->sc_txd[cur].d_len = 0; } else { sc->sc_tx_timer = 5; //ifp->if_timer = 1; } }}/************************************************************//* wi_info_intr *//************************************************************/static void wi_info_intr(struct wi_softc *sc){ struct ieee80211com *ic = &sc->sc_ic; //struct ifnet *ifp = &ic->ic_if; //int i, len, off; /* Harald: Not used */ int fid; u_int16_t ltbuf[2]; u_int16_t stat; //u_int32_t *ptr; /* Harald: Not used. */ fid = CSR_READ_2(sc, WI_INFO_FID); wi_read_bap(sc, fid, 0, ltbuf, sizeof(ltbuf)); switch (le16toh(ltbuf[1])) { case WI_INFO_LINK_STAT: wi_read_bap(sc, fid, sizeof(ltbuf), &stat, sizeof(stat));#if (WLAN_ENABLE_LINK_STATUS >= 1) Debug(("wi_info_intr: LINK_STAT 0x%x\n", le16toh(stat)));#endif /* (WLAN_ENABLE_LINK_STATUS >= 1) */ switch (le16toh(stat)) { case WI_INFO_LINK_STAT_CONNECTED: sc->sc_flags &= ~WI_FLAGS_OUTRANGE; if (ic->ic_state == IEEE80211_S_RUN && ic->ic_opmode != IEEE80211_M_IBSS) { break; } /* * FALLTHROUGH */ case WI_INFO_LINK_STAT_AP_CHG: ieee80211_new_state(ic, IEEE80211_S_RUN, -1); break; case WI_INFO_LINK_STAT_AP_INR: sc->sc_flags &= ~WI_FLAGS_OUTRANGE; break; case WI_INFO_LINK_STAT_AP_OOR: if (sc->sc_firmware_type == WI_SYMBOL && sc->sc_scan_timer > 0) { if (wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_HOST_SCAN_RESULTS, 0, 0) != 0) { sc->sc_scan_timer = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -