📄 an.c
字号:
CSR_WRITE_2(sc, AN_PARAM0, val);
CSR_WRITE_2(sc, AN_PARAM1, 0);
CSR_WRITE_2(sc, AN_PARAM2, 0);
DELAY(10);
CSR_WRITE_2(sc, AN_COMMAND, cmd);
DELAY(10);
for (i = AN_TIMEOUT; i--; DELAY(10)) {
if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
break;
else {
if (CSR_READ_2(sc, AN_COMMAND) == cmd) {
DELAY(10);
CSR_WRITE_2(sc, AN_COMMAND, cmd);
}
}
}
stat = CSR_READ_2(sc, AN_STATUS);
/* clear stuck command busy if needed */
if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) {
CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
}
/* Ack the command */
CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);
if (i <= 0)
return(ETIMEDOUT);
if (stat & AN_STAT_CMD_RESULT)
return(EIO);
return(0);
}
/*
* This reset sequence may look a little strange, but this is the
* most reliable method I've found to really kick the NIC in the
* head and force it to reboot correctly.
*/
void
an_reset(sc)
struct an_softc *sc;
{
if (sc->an_gone)
return;
/*printf("ena ");*/
an_cmd(sc, AN_CMD_ENABLE, 0);
/* printf("rst ");*/
an_cmd(sc, AN_CMD_FW_RESTART, 0);
/*printf("nop ");*/
an_cmd(sc, AN_CMD_NOOP2, 0);
if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT)
printf("%s: reset failed\n", sc->sc_dev.dv_xname);
an_cmd(sc, AN_CMD_DISABLE, 0);
}
/*
* Read an LTV record from the NIC.
*/
int
an_read_record(sc, ltv)
struct an_softc *sc;
struct an_ltv_gen *ltv;
{
u_int16_t *ptr, len;
int i;
u_int16_t ltv_data_length;
if (ltv->an_len < 4 || ltv->an_type == 0)
return(EINVAL);
/* Tell the NIC to enter record read mode. */
if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) {
printf("%s: RID 0x%04x access failed\n",
sc->sc_dev.dv_xname, ltv->an_type);
return(EIO);
}
/* Seek to the record. */
if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) {
printf("%s: RID 0x%04x seek to record failed\n",
sc->sc_dev.dv_xname, ltv->an_type);
return(EIO);
}
/*
* Read the length to make sure it
* matches what we expect (this verifies that we have enough
* room to hold all of the returned data).
*/
len = CSR_READ_2(sc, AN_DATA1);
/*
* Work out record's data length, which is struct length - type word
* as we have just read the length.
*/
ltv_data_length = ltv->an_len - sizeof(u_int16_t);
if (len > ltv_data_length) {
printf("%s: RID 0x%04x record length mismatch -- expected %d, "
"got %d\n", sc->sc_dev.dv_xname, ltv->an_type,
ltv_data_length, len);
return(ENOSPC);
}
/* Now read the data. */
ptr = ltv->an_val;
for (i = 0; i < (len - 1) >> 1; i++)
ptr[i] = CSR_READ_2(sc, AN_DATA1);
#if BYTE_ORDER == BIG_ENDIAN
switch (ltv->an_type) {
case AN_RID_GENCONFIG:
an_swap16(<v->an_val[4], 7); /* an_macaddr, an_rates */
an_swap16(<v->an_val[63], 8); /* an_nodename */
break;
case AN_RID_SSIDLIST:
an_swap16(<v->an_val[1], 16); /* an_ssid1 */
an_swap16(<v->an_val[18], 16); /* an_ssid2 */
an_swap16(<v->an_val[35], 16); /* an_ssid3 */
break;
case AN_RID_APLIST:
an_swap16(ltv->an_val, 12);
break;
case AN_RID_DRVNAME:
an_swap16(ltv->an_val, 8);
break;
case AN_RID_CAPABILITIES:
an_swap16(ltv->an_val, 2); /* an_oui */
an_swap16(<v->an_val[3], 34); /* an_manufname .. an_aironetaddr */
an_swap16(<v->an_val[39], 8); /* an_callid .. an_tx_diversity */
break;
case AN_RID_STATUS:
an_swap16(<v->an_val[0], 3); /* an_macaddr */
an_swap16(<v->an_val[7], 36); /* an_ssid .. an_prev_bssid3 */
an_swap16(<v->an_val[0x74/2], 2); /* an_ap_ip_addr */
break;
case AN_RID_WEP_VOLATILE:
case AN_RID_WEP_PERMANENT:
an_swap16(<v->an_val[1], 3); /* an_mac_addr */
an_swap16(<v->an_val[5], 6);
break;
case AN_RID_32BITS_CUM:
for (i = 0x60; i--; ) {
u_int16_t t = ltv->an_val[i * 2] ^ ltv->an_val[i * 2 + 1];
ltv->an_val[i * 2] ^= t;
ltv->an_val[i * 2 + 1] ^= t;
}
break;
}
#endif
return(0);
}
/*
* Same as read, except we inject data instead of reading it.
*/
int
an_write_record(sc, ltv)
struct an_softc *sc;
struct an_ltv_gen *ltv;
{
u_int16_t *ptr;
int i;
if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type))
return(EIO);
if (an_seek(sc, ltv->an_type, 0, AN_BAP1))
return(EIO);
#if BYTE_ORDER == BIG_ENDIAN
switch (ltv->an_type) {
case AN_RID_GENCONFIG:
an_swap16(<v->an_val[4], 7); /* an_macaddr, an_rates */
an_swap16(<v->an_val[63], 8); /* an_nodename */
break;
case AN_RID_SSIDLIST:
an_swap16(<v->an_val[1], 16); /* an_ssid1 */
an_swap16(<v->an_val[18], 16); /* an_ssid2 */
an_swap16(<v->an_val[35], 16); /* an_ssid3 */
break;
case AN_RID_APLIST:
an_swap16(ltv->an_val, 12);
break;
case AN_RID_DRVNAME:
an_swap16(ltv->an_val, 8);
break;
case AN_RID_CAPABILITIES:
an_swap16(ltv->an_val, 2); /* an_oui */
an_swap16(<v->an_val[3], 34); /* an_manufname .. an_aironetaddr */
an_swap16(<v->an_val[39], 8); /* an_callid .. an_tx_diversity */
break;
case AN_RID_STATUS:
an_swap16(<v->an_val[0], 3); /* an_macaddr */
an_swap16(<v->an_val[7], 36); /* an_ssid .. an_prev_bssid3 */
an_swap16(<v->an_val[0x74/2], 2); /* an_ap_ip_addr */
break;
case AN_RID_WEP_VOLATILE:
case AN_RID_WEP_PERMANENT:
an_swap16(<v->an_val[1], 3); /* an_mac_addr */
an_swap16(<v->an_val[5], 6);
break;
}
#endif
CSR_WRITE_2(sc, AN_DATA1, ltv->an_len);
ptr = ltv->an_val;
for (i = 0; i < (ltv->an_len - 1) >> 1; i++)
CSR_WRITE_2(sc, AN_DATA1, ptr[i]);
if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type))
return(EIO);
return(0);
}
int
an_seek(sc, id, off, chan)
struct an_softc *sc;
int id, off, chan;
{
int i;
int selreg, offreg;
switch (chan) {
case AN_BAP0:
selreg = AN_SEL0;
offreg = AN_OFF0;
break;
case AN_BAP1:
selreg = AN_SEL1;
offreg = AN_OFF1;
break;
default:
printf("%s: invalid data path: %x\n",
sc->sc_dev.dv_xname, chan);
return (EIO);
}
CSR_WRITE_2(sc, selreg, id);
CSR_WRITE_2(sc, offreg, off);
for (i = AN_TIMEOUT; i--; DELAY(10)) {
if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR)))
break;
}
if (i <= 0)
return(ETIMEDOUT);
return (0);
}
int
an_read_data(sc, id, off, buf, len)
struct an_softc *sc;
int id, off;
caddr_t buf;
int len;
{
if (off != -1 && an_seek(sc, id, off, AN_BAP1))
return(EIO);
bus_space_read_raw_multi_2(sc->an_btag, sc->an_bhandle,
AN_DATA1, buf, len & ~1);
if (len & 1)
((u_int8_t *)buf)[len - 1] = CSR_READ_1(sc, AN_DATA1);
return (0);
}
int
an_write_data(sc, id, off, buf, len)
struct an_softc *sc;
int id, off;
caddr_t buf;
int len;
{
if (off != -1 && an_seek(sc, id, off, AN_BAP0))
return(EIO);
bus_space_write_raw_multi_2(sc->an_btag, sc->an_bhandle,
AN_DATA0, buf, len & ~1);
if (len & 1)
CSR_WRITE_1(sc, AN_DATA0, ((u_int8_t *)buf)[len - 1]);
return (0);
}
/*
* Allocate a region of memory inside the NIC and zero
* it out.
*/
int
an_alloc_nicmem(sc, len, id)
struct an_softc *sc;
int len;
int *id;
{
int i;
if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) {
printf("%s: failed to allocate %d bytes on NIC\n",
sc->sc_dev.dv_xname, len);
return(ENOMEM);
}
for (i = AN_TIMEOUT; i--; DELAY(10)) {
if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_ALLOC)
break;
}
if (i <= 0)
return(ETIMEDOUT);
CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC);
*id = CSR_READ_2(sc, AN_ALLOC_FID);
if (an_seek(sc, *id, 0, AN_BAP0))
return(EIO);
bus_space_set_multi_2(sc->an_btag, sc->an_bhandle,
AN_DATA0, 0, len / 2);
CSR_WRITE_1(sc, AN_DATA0, 0);
return(0);
}
void
an_setdef(sc, areq)
struct an_softc *sc;
struct an_req *areq;
{
struct sockaddr_dl *sdl;
struct ifaddr *ifa;
struct ifnet *ifp;
struct an_ltv_genconfig *cfg;
struct an_ltv_ssidlist *ssid;
struct an_ltv_aplist *ap;
struct an_ltv_gen *sp;
extern struct ifaddr **ifnet_addrs;
ifp = &sc->arpcom.ac_if;
switch (areq->an_type) {
case AN_RID_GENCONFIG:
cfg = (struct an_ltv_genconfig *)areq;
ifa = ifnet_addrs[ifp->if_index];
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
bcopy((char *)&cfg->an_macaddr, (char *)&sc->arpcom.ac_enaddr,
ETHER_ADDR_LEN);
bcopy((char *)&cfg->an_macaddr, LLADDR(sdl), ETHER_ADDR_LEN);
bcopy((char *)cfg, (char *)&sc->an_config,
sizeof(struct an_ltv_genconfig));
break;
case AN_RID_SSIDLIST:
ssid = (struct an_ltv_ssidlist *)areq;
bcopy((char *)ssid, (char *)&sc->an_ssidlist,
sizeof(struct an_ltv_ssidlist));
break;
case AN_RID_APLIST:
ap = (struct an_ltv_aplist *)areq;
bcopy((char *)ap, (char *)&sc->an_aplist,
sizeof(struct an_ltv_aplist));
break;
case AN_RID_TX_SPEED:
sp = (struct an_ltv_gen *)areq;
sc->an_tx_rate = sp->an_val[0];
break;
case AN_RID_WEP_VOLATILE:
/* Disable the MAC */
an_cmd(sc, AN_CMD_DISABLE, 0);
/* Just write the key, we dont' want to save it */
an_write_record(sc, (struct an_ltv_gen *)areq);
/* Turn the MAC back on */
an_cmd(sc, AN_CMD_ENABLE, 0);
break;
case AN_RID_WEP_PERMANENT:
/* Disable the MAC */
// an_cmd(sc, AN_CMD_DISABLE, 0);
/* Just write the key, the card will save it in this mode */
an_write_record(sc, (struct an_ltv_gen *)areq);
/* Turn the MAC back on */
// an_cmd(sc, AN_CMD_ENABLE, 0);
return;
break;
default:
printf("%s: unknown RID: %x\n",
sc->sc_dev.dv_xname, areq->an_type);
return;
}
/* Reinitialize the card. */
if (ifp->if_flags & IFF_UP)
an_init(sc);
}
/*
* We can't change the NIC configuration while the MAC is enabled,
* so in order to turn on RX monitor mode, we have to turn the MAC
* off first.
*/
void
an_promisc(sc, promisc)
struct an_softc *sc;
int promisc;
{
struct an_ltv_genconfig genconf;
/* Disable the MAC. */
an_cmd(sc, AN_CMD_DISABLE, 0);
/* Set RX mode. */
if (promisc &&
!(sc->an_config.an_rxmode & AN_RXMODE_LAN_MONITOR_CURBSS) ) {
sc->an_rxmode = sc->an_config.an_rxmode;
sc->an_config.an_rxmode |=
AN_RXMODE_LAN_MONITOR_CURBSS;
} else {
sc->an_config.an_rxmode = sc->an_rxmode;
}
/* Transfer the configuration to the NIC */
genconf = sc->an_config;
genconf.an_len = sizeof(struct an_ltv_genconfig);
genconf.an_type = AN_RID_GENCONFIG;
if (an_write_record(sc, (struct an_ltv_gen *)&genconf)) {
printf("%s: failed to set configuration\n",
sc->sc_dev.dv_xname);
return;
}
/* Turn the MAC back on. */
an_cmd(sc, AN_CMD_ENABLE, 0);
}
int
an_ioctl(ifp, command, data)
struct ifnet *ifp;
u_long command;
caddr_t data;
{
int s, error = 0;
struct an_softc *sc;
struct an_req areq;
struct ifreq *ifr;
struct proc *p = curproc;
struct ifaddr *ifa = (struct ifaddr *)data;
s = splimp();
sc = ifp->if_softc;
ifr = (struct ifreq *)data;
if (sc->an_gone) {
splx(s);
return(ENODEV);
}
if ((error = ether_ioctl(ifp, &sc->arpcom, command, data)) > 0) {
splx(s);
return error;
}
switch(command) {
case SIOCSIFADDR:
ifp->if_flags |= IFF_UP;
switch (ifa->ifa_addr->sa_family) {
#ifdef INET
case AF_INET:
an_init(sc);
arp_ifinit(&sc->arpcom, ifa);
break;
#endif
default:
an_init(sc);
break;
}
break;
case SIOCSIFFLAGS:
if (ifp->if_flags & IFF_UP) {
if (ifp->if_flags & IFF_RUNNING &&
ifp->if_flags & IFF_PROMISC &&
!(sc->an_if_flags & IFF_PROMISC)) {
an_promisc(sc, 1);
} else if (ifp->if_flags & IFF_RUNNING &&
!(ifp->if_flags & IFF_PROMISC) &&
sc->an_if_flags & IFF_PROMISC) {
an_promisc(sc, 0);
an_reset(sc);
}
an_init(sc);
} else {
if (ifp->if_flags & IFF_RUNNING)
an_stop(sc);
}
sc->an_if_flags = ifp->if_flags;
error = 0;
break;
case SIOCSIFMEDIA:
case SIOCGIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &sc->an_ifmedia, command);
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
/* The Aironet has no multicast filter. */
error = 0;
break;
case SIOCGAIRONET:
error = copyin(ifr->ifr_data, &areq, sizeof(areq));
if (error)
break;
#ifdef ANCACHE
if (areq.an_type == AN_RID_ZERO_CACHE) {
error = suser(p->p_ucred, &p->p_acflag);
if (error)
break;
sc->an_sigitems = sc->an_nextitem = 0;
break;
} else if (areq.an_type == AN_RID_READ_CACHE) {
char *pt = (char *)&areq.an_val;
bcopy((char *)&sc->an_sigitems, (char *)pt,
sizeof(int));
pt += sizeof(int);
areq.an_len = sizeof(int) / 2;
bcopy((char *)&sc->an_sigcache, (char *)pt,
sizeof(struct an_sigcache) * sc->an_sigitems);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -