diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2004-10-27 21:22:15 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2004-10-27 21:22:15 +0000 |
commit | d865a8383a71b9335c4ce381656d041fdbc03dbf (patch) | |
tree | 9968f7926cd501591643ce824179e10fd1097c34 | |
parent | 8e090bce28179d99854dbc51a3e4fc7f18375d67 (diff) |
Read MAC address from EEPROM in ipw_attach(). The address is now known
before the firmware has been sent. Imported from iwi.
-rw-r--r-- | sys/dev/pci/if_ipw.c | 85 | ||||
-rw-r--r-- | sys/dev/pci/if_ipwreg.h | 27 |
2 files changed, 101 insertions, 11 deletions
diff --git a/sys/dev/pci/if_ipw.c b/sys/dev/pci/if_ipw.c index 1a7e16a5022..8d5a8286e6c 100644 --- a/sys/dev/pci/if_ipw.c +++ b/sys/dev/pci/if_ipw.c @@ -1,4 +1,4 @@ -/* $Id: if_ipw.c,v 1.12 2004/10/27 21:21:16 damien Exp $ */ +/* $Id: if_ipw.c,v 1.13 2004/10/27 21:22:14 damien Exp $ */ /*- * Copyright (c) 2004 @@ -82,6 +82,7 @@ int ipw_detach(struct device *, int); int ipw_media_change(struct ifnet *); void ipw_media_status(struct ifnet *, struct ifmediareq *); int ipw_newstate(struct ieee80211com *, enum ieee80211_state, int); +u_int16_t ipw_read_prom_word(struct ipw_softc *, u_int8_t); void ipw_command_intr(struct ipw_softc *, struct ipw_soft_buf *); void ipw_newstate_intr(struct ipw_softc *, struct ipw_soft_buf *); void ipw_data_intr(struct ipw_softc *, struct ipw_status *, @@ -170,6 +171,7 @@ ipw_attach(struct device *parent, struct device *self, void *aux) bus_addr_t base; pci_intr_handle_t ih; pcireg_t data; + u_int16_t val; int error, i; sc->sc_pct = pa->pa_pc; @@ -215,6 +217,11 @@ ipw_attach(struct device *parent, struct device *self, void *aux) } printf(": %s\n", intrstr); + if (ipw_reset(sc) != 0) { + printf(": could not reset adapter\n"); + return; + } + ic->ic_phytype = IEEE80211_T_DS; ic->ic_opmode = IEEE80211_M_STA; ic->ic_state = IEEE80211_S_INIT; @@ -223,6 +230,17 @@ ipw_attach(struct device *parent, struct device *self, void *aux) ic->ic_caps = IEEE80211_C_IBSS | IEEE80211_C_MONITOR | IEEE80211_C_PMGT | IEEE80211_C_TXPMGT | IEEE80211_C_WEP; + /* read MAC address from EEPROM */ + val = ipw_read_prom_word(sc, IPW_EEPROM_MAC + 0); + ic->ic_myaddr[0] = val >> 8; + ic->ic_myaddr[1] = val & 0xff; + val = ipw_read_prom_word(sc, IPW_EEPROM_MAC + 1); + ic->ic_myaddr[2] = val >> 8; + ic->ic_myaddr[3] = val & 0xff; + val = ipw_read_prom_word(sc, IPW_EEPROM_MAC + 2); + ic->ic_myaddr[4] = val >> 8; + ic->ic_myaddr[5] = val & 0xff; + /* set supported .11b rates */ ic->ic_sup_rates[IEEE80211_MODE_11B] = ipw_rateset_11b; @@ -397,6 +415,62 @@ ipw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) return 0; } +/* + * Read 16 bits at address 'addr' from the Microwire EEPROM. + * DON'T PLAY WITH THIS CODE UNLESS YOU KNOW *EXACTLY* WHAT YOU'RE DOING! + */ +u_int16_t +ipw_read_prom_word(struct ipw_softc *sc, u_int8_t addr) +{ + u_int32_t tmp; + u_int16_t val; + int n; + + /* Clock C once before the first command */ + IPW_EEPROM_CTL(sc, 0); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_C); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S); + + /* Write start bit (1) */ + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_D); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_D | IPW_EEPROM_C); + + /* Write READ opcode (10) */ + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_D); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_D | IPW_EEPROM_C); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_C); + + /* Write address A7-A0 */ + for (n = 7; n >= 0; n--) { + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | + (((addr >> n) & 1) << IPW_EEPROM_SHIFT_D)); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | + (((addr >> n) & 1) << IPW_EEPROM_SHIFT_D) | IPW_EEPROM_C); + } + + IPW_EEPROM_CTL(sc, IPW_EEPROM_S); + + /* Read data Q15-Q0 */ + val = 0; + for (n = 15; n >= 0; n--) { + IPW_EEPROM_CTL(sc, IPW_EEPROM_S | IPW_EEPROM_C); + IPW_EEPROM_CTL(sc, IPW_EEPROM_S); + tmp = MEM_READ_4(sc, IPW_MEM_EEPROM_CTL); + val |= ((tmp & IPW_EEPROM_Q) >> IPW_EEPROM_SHIFT_Q) << n; + } + + IPW_EEPROM_CTL(sc, 0); + + /* Clear Chip Select and clock C */ + IPW_EEPROM_CTL(sc, IPW_EEPROM_S); + IPW_EEPROM_CTL(sc, 0); + IPW_EEPROM_CTL(sc, IPW_EEPROM_C); + + return letoh16(val); +} + void ipw_command_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf) { @@ -1876,9 +1950,8 @@ int ipw_init(struct ifnet *ifp) { struct ipw_softc *sc = ifp->if_softc; - struct ieee80211com *ic = &sc->sc_ic; struct ipw_firmware *fw = &sc->fw; - int error, len; + int error; /* exit immediately if firmware has not been ioctl'd */ if (!(sc->flags & IPW_FLAG_FW_CACHED)) { @@ -1923,12 +1996,6 @@ ipw_init(struct ifnet *ifp) ipw_write_table1(sc, IPW_INFO_LOCK, 0); - /* Retrieve adapter MAC address */ - len = IEEE80211_ADDR_LEN; - ipw_read_table2(sc, IPW_INFO_ADAPTER_MAC, ic->ic_myaddr, &len); - - IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), ic->ic_myaddr); - if ((error = ipw_config(sc)) != 0) { printf("%s: device configuration failed\n", sc->sc_dev.dv_xname); diff --git a/sys/dev/pci/if_ipwreg.h b/sys/dev/pci/if_ipwreg.h index 7ed3149e5f2..2252fb0c1c5 100644 --- a/sys/dev/pci/if_ipwreg.h +++ b/sys/dev/pci/if_ipwreg.h @@ -1,4 +1,4 @@ -/* $Id: if_ipwreg.h,v 1.5 2004/10/27 21:21:16 damien Exp $ */ +/* $Id: if_ipwreg.h,v 1.6 2004/10/27 21:22:14 damien Exp $ */ /*- * Copyright (c) 2004 @@ -102,7 +102,6 @@ #define IPW_INFO_CURRENT_TX_RATE 768 /* table2 offsets */ -#define IPW_INFO_ADAPTER_MAC 8 #define IPW_INFO_CURRENT_SSID 48 #define IPW_INFO_CURRENT_BSSID 112 @@ -251,6 +250,22 @@ struct ipw_configuration { u_int32_t ibss_chan; } __attribute__((__packed__)); +/* EEPROM = Electrically Erasable Programmable Read-Only Memory */ + +#define IPW_MEM_EEPROM_CTL 0x00300040 + +#define IPW_EEPROM_MAC 0x21 + +#define IPW_EEPROM_DELAY 1 /* minimum hold time (microsecond) */ + +#define IPW_EEPROM_C (1 << 0) /* Serial Clock */ +#define IPW_EEPROM_S (1 << 1) /* Chip Select */ +#define IPW_EEPROM_D (1 << 2) /* Serial data input */ +#define IPW_EEPROM_Q (1 << 4) /* Serial data output */ + +#define IPW_EEPROM_SHIFT_D 2 +#define IPW_EEPROM_SHIFT_Q 4 + /* * control and status registers access macros */ @@ -299,3 +314,11 @@ struct ipw_configuration { CSR_WRITE_MULTI_1((sc), IPW_CSR_INDIRECT_DATA, (buf), (len)); \ } while (/* CONSTCOND */0) +/* + * EEPROM access macro + */ +#define IPW_EEPROM_CTL(sc, val) do { \ + MEM_WRITE_4((sc), IPW_MEM_EEPROM_CTL, (val)); \ + DELAY(IPW_EEPROM_DELAY); \ +} while (0) + |