📄 airo.c
字号:
bap_setup (apriv, fid, 0x38, BAP0); bap_read (apriv, buffer,len + hdrlen,BAP0); } OUT4500( apriv, EVACK, EV_RX);#ifdef WIRELESS_SPY if (apriv->spy_number > 0) { int i; char *sa; sa = (char*)buffer + ((dev->type == ARPHRD_IEEE80211) ? 10 : 6); for (i=0; i<apriv->spy_number; i++) if (!memcmp(sa,apriv->spy_address[i],6)) { apriv->spy_stat[i].qual = hdr.rssi[0]; if (apriv->rssi) apriv->spy_stat[i].level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm; else apriv->spy_stat[i].level = (hdr.rssi[1] + 321) / 2; apriv->spy_stat[i].noise = 0; apriv->spy_stat[i].updated = 3; break; } }#endif /* WIRELESS_SPY */ dev->last_rx = jiffies; skb->dev = dev; skb->ip_summed = CHECKSUM_NONE; if (dev->type == ARPHRD_IEEE80211) { skb->mac.raw = skb->data; skb_pull (skb, hdrlen); skb->pkt_type = PACKET_OTHERHOST; skb->protocol = htons(ETH_P_802_2); } else skb->protocol = eth_type_trans(skb,dev); netif_rx( skb ); } else OUT4500( apriv, EVACK, EV_RX); } /* Check to see if a packet has been transmitted */ if ( status & ( EV_TX|EV_TXEXC ) ) { int i; int len = 0; int index = -1; fid = IN4500(apriv, TXCOMPLFID); for( i = 0; i < MAX_FIDS; i++ ) { if ( ( apriv->fids[i] & 0xffff ) == fid ) { len = apriv->fids[i] >> 16; index = i; /* Set up to be used again */ apriv->fids[i] &= 0xffff; } } if (index != -1) netif_wake_queue(dev); if ((status & EV_TXEXC) && (bap_setup(apriv, fid, 4, BAP1) == SUCCESS)) { u16 status; bap_read(apriv, &status, 2, BAP1); if (le16_to_cpu(status) & 2) apriv->stats.tx_aborted_errors++; if (le16_to_cpu(status) & 4) apriv->stats.tx_heartbeat_errors++; if (le16_to_cpu(status) & 0x10) apriv->stats.tx_carrier_errors++; } OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC)); if (index==-1) { printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" ); } } if ( status & ~STATUS_INTS ) OUT4500( apriv, EVACK, status & ~STATUS_INTS); if ( status & ~STATUS_INTS & ~IGNORE_INTS ) printk( KERN_WARNING "airo: Got weird status %x\n", status & ~STATUS_INTS & ~IGNORE_INTS ); } if (savedInterrupts) OUT4500( apriv, EVINTEN, savedInterrupts ); /* done.. */ return;}/* * Routines to talk to the card *//* * This was originally written for the 4500, hence the name * NOTE: If use with 8bit mode and SMP bad things will happen! * Why would some one do 8 bit IO in an SMP machine?!? */static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) { if ( !do8bitIO ) outw( val, ai->dev->base_addr + reg ); else { outb( val & 0xff, ai->dev->base_addr + reg ); outb( val >> 8, ai->dev->base_addr + reg + 1 ); }}static u16 IN4500( struct airo_info *ai, u16 reg ) { unsigned short rc; if ( !do8bitIO ) rc = inw( ai->dev->base_addr + reg ); else { rc = inb( ai->dev->base_addr + reg ); rc += ((int)inb( ai->dev->base_addr + reg + 1 )) << 8; } return rc;}static int enable_MAC( struct airo_info *ai, Resp *rsp ) { Cmd cmd; if (ai->flags&FLAG_RADIO_OFF) return SUCCESS; memset(&cmd, 0, sizeof(cmd)); cmd.cmd = MAC_ENABLE; return lock_issuecommand(ai, &cmd, rsp);}static void disable_MAC( struct airo_info *ai ) { Cmd cmd; Resp rsp; memset(&cmd, 0, sizeof(cmd)); cmd.cmd = MAC_DISABLE; // disable in case already enabled lock_issuecommand(ai, &cmd, &rsp);}static void enable_interrupts( struct airo_info *ai ) { /* Reset the status register */ u16 status = IN4500( ai, EVSTAT ); OUT4500( ai, EVACK, status ); /* Enable the interrupts */ OUT4500( ai, EVINTEN, STATUS_INTS ); /* Note there is a race condition between the last two lines that I dont know how to get rid of right now... */}static void disable_interrupts( struct airo_info *ai ) { OUT4500( ai, EVINTEN, 0 );}static u16 setup_card(struct airo_info *ai, u8 *mac, ConfigRid *config){ Cmd cmd; Resp rsp; ConfigRid cfg; int status; int i; SsidRid mySsid; u16 lastindex; WepKeyRid wkr; int rc; memset( &mySsid, 0, sizeof( mySsid ) ); if (ai->flash) { kfree (ai->flash); ai->flash = NULL; } /* The NOP is the first step in getting the card going */ cmd.cmd = NOP; cmd.parm0 = cmd.parm1 = cmd.parm2 = 0; if ( lock_issuecommand( ai, &cmd, &rsp ) != SUCCESS ) { return ERROR; } memset(&cmd, 0, sizeof(cmd)); cmd.cmd = MAC_DISABLE; // disable in case already enabled if ( lock_issuecommand( ai, &cmd, &rsp ) != SUCCESS ) { return ERROR; } // Let's figure out if we need to use the AUX port cmd.cmd = CMD_ENABLEAUX; if (lock_issuecommand(ai, &cmd, &rsp) != SUCCESS) { printk(KERN_ERR "airo: Error checking for AUX port\n"); return ERROR; } if (!aux_bap || rsp.status & 0xff00) { ai->bap_read = fast_bap_read; printk(KERN_DEBUG "airo: Doing fast bap_reads\n"); } else { ai->bap_read = aux_bap_read; printk(KERN_DEBUG "airo: Doing AUX bap_reads\n"); } if ( config->len ) { cfg = *config; } else { tdsRssiRid rssi_rid; // general configuration (read/modify/write) status = readConfigRid(ai, &cfg); if ( status != SUCCESS ) return ERROR; status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid)); if ( status == SUCCESS ) { if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL) memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); } else { CapabilityRid cap_rid; if (ai->rssi) { kfree(ai->rssi); ai->rssi = NULL; } status = readCapabilityRid(ai, &cap_rid); if ((status == SUCCESS) && (cap_rid.softCap & 8)) cfg.rmode |= RXMODE_NORMALIZED_RSSI; else printk(KERN_WARNING "airo: unknown received signal level scale\n"); } cfg.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS; /* Save off the MAC */ for( i = 0; i < 6; i++ ) { mac[i] = cfg.macAddr[i]; } /* Check to see if there are any insmod configured rates to add */ if ( rates ) { int i = 0; if ( rates[0] ) memset(cfg.rates,0,sizeof(cfg.rates)); for( i = 0; i < 8 && rates[i]; i++ ) { cfg.rates[i] = rates[i]; } } if ( basic_rate > 0 ) { int i; for( i = 0; i < 8; i++ ) { if ( cfg.rates[i] == basic_rate || !cfg.rates ) { cfg.rates[i] = basic_rate | 0x80; break; } } } cfg.authType = ai->authtype; *config = cfg; } /* Setup the SSIDs if present */ if ( ssids[0] ) { int i = 0; for( i = 0; i < 3 && ssids[i]; i++ ) { mySsid.ssids[i].len = strlen(ssids[i]); if ( mySsid.ssids[i].len > 32 ) mySsid.ssids[i].len = 32; memcpy(mySsid.ssids[i].ssid, ssids[i], mySsid.ssids[i].len); mySsid.ssids[i].len = mySsid.ssids[i].len; } } status = writeConfigRid(ai, &cfg); if ( status != SUCCESS ) return ERROR; /* Set up the SSID list */ status = writeSsidRid(ai, &mySsid); if ( status != SUCCESS ) return ERROR; /* Grab the initial wep key, we gotta save it for auto_wep */ rc = readWepKeyRid(ai, &wkr, 1); if (rc == SUCCESS) do { lastindex = wkr.kindex; if (wkr.kindex == 0xffff) { ai->defindex = wkr.mac[0]; } rc = readWepKeyRid(ai, &wkr, 0); } while(lastindex != wkr.kindex); if (auto_wep && !timer_pending(&ai->timer)) { ai->timer.expires = RUN_AT(HZ*3); add_timer(&ai->timer); } return SUCCESS;}static u16 lock_issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { int rc; long flags; spin_lock_irqsave(&ai->main_lock, flags); rc = issuecommand(ai, pCmd, pRsp); spin_unlock_irqrestore(&ai->main_lock, flags); return rc;}static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { // Im really paranoid about letting it run forever! int max_tries = 600000; OUT4500(ai, PARAM0, pCmd->parm0); OUT4500(ai, PARAM1, pCmd->parm1); OUT4500(ai, PARAM2, pCmd->parm2); OUT4500(ai, COMMAND, pCmd->cmd); while ( max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) { if ( IN4500(ai, COMMAND) == pCmd->cmd) { // PC4500 didn't notice command, try again OUT4500(ai, COMMAND, pCmd->cmd); } } if ( max_tries == -1 ) { printk( KERN_ERR "airo: Max tries exceeded when issueing command\n" ); return ERROR; } // command completed pRsp->status = IN4500(ai, STATUS); pRsp->rsp0 = IN4500(ai, RESP0); pRsp->rsp1 = IN4500(ai, RESP1); pRsp->rsp2 = IN4500(ai, RESP2); // clear stuck command busy if necessary if (IN4500(ai, COMMAND) & COMMAND_BUSY) { OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); } // acknowledge processing the status/response OUT4500(ai, EVACK, EV_CMD); return SUCCESS;}/* Sets up the bap to start exchange data. whichbap should * be one of the BAP0 or BAP1 defines. Locks should be held before * calling! */static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap ){ int timeout = 50; int max_tries = 3; OUT4500(ai, SELECT0+whichbap, rid); OUT4500(ai, OFFSET0+whichbap, offset); while (1) { int status = IN4500(ai, OFFSET0+whichbap); if (status & BAP_BUSY) { /* This isn't really a timeout, but its kinda close */ if (timeout--) { continue; } } else if ( status & BAP_ERR ) { /* invalid rid or offset */ printk( KERN_ERR "airo: BAP error %x %d\n", status, whichbap ); return ERROR; } else if (status & BAP_DONE) { // success return SUCCESS; } if ( !(max_tries--) ) { printk( KERN_ERR "airo: BAP setup error too many retries\n" ); return ERROR; } // -- PC4500 missed it, try again OUT4500(ai, SELECT0+whichbap, rid); OUT4500(ai, OFFSET0+whichbap, offset); timeout = 50; }}/* should only be called by aux_bap_read. This aux function and the following use concepts not documented in the developers guide. I got them from a patch given to my by Aironet */static u16 aux_setup(struct airo_info *ai, u16 page, u16 offset, u16 *len){ u16 next; OUT4500(ai, AUXPAGE, page); OUT4500(ai, AUXOFF, 0); next = IN4500(ai, AUXDATA); *len = IN4500(ai, AUXDATA)&0xff; if (offset != 4) OUT4500(ai, AUXOFF, offset); return next;}/* requires call to bap_setup() first */static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen, int whichbap){ u16 len; u16 page; u16 offset; u16 next; int words; int i; long flags; spin_lock_irqsave(&ai->aux_lock, flags); page = IN4500(ai, SWS0+whichbap); offset = IN4500(ai, SWS2+whichbap); next = aux_setup(ai, page, offset, &len); words = (bytelen+1)>>1; for (i=0; i<words;) { int count; count = (len>>1) < (words-i) ? (len>>1) : (words-i); if ( !do8bitIO ) insw( ai->dev->base_addr+DATA0+whichbap, pu16Dst+i,count ); else insb( ai->dev->base_addr+DATA0+whichbap, pu16Dst+i, count << 1 ); i += count; if (i<words) { next = aux_setup(ai, next, 4, &len); } } spin_unlock_irqrestore(&ai->aux_lock, flags); return SUCCESS;}/* requires call to bap_setup() first */static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen, int whichbap){ bytelen = (bytelen + 1) & (~1); // round up to even value if ( !do8bitIO ) insw( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1 ); else insb( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen ); return SUCCESS;}/* requires call to bap_setup() first */static int bap_write(struct airo_info *ai, const u16 *pu16Src, int bytelen, int whichbap){ bytelen = (bytelen + 1) & (~1); // round up to even value if ( !do8bitIO ) outsw( ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen>>1 ); else outsb( ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen ); return SUCCESS;}static int PC4500_accessrid(struct airo_info *ai, u16 rid, u16 accmd){ Cmd cmd; /* for issuing commands */ Resp rsp; /* response from commands */ u16 status; memset(&cmd, 0, sizeof(cmd)); cmd.cmd = accmd; cmd.parm0 = rid; status = issuecommand(ai, &cmd, &rsp); if (status != 0) return status; if ( (rsp.status & 0x7F00) != 0) { return (accmd << 8) + (rsp.rsp0 & 0xFF); } return 0;}/* Note, that we are using BAP1 which is also used by transmit, so * we must get a lock. */static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len){ u16 status; long flags; int rc = SUCCESS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -