📄 airo.c
字号:
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 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { // Im really paranoid about letting it run forever! int max_tries = 600000; int rc = SUCCESS; int flags; spin_lock_irqsave(&ai->cmd_lock, flags); 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" ); rc = ERROR; goto done; } // 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);done: spin_unlock_irqrestore(&ai->cmd_lock, flags); return rc;}/* 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; int 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; int flags; int rc = SUCCESS; spin_lock_irqsave(&ai->bap1_lock, flags); if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != SUCCESS) { rc = status; goto done; } if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) { rc = ERROR; goto done; } // read the rid length field bap_read(ai, pBuf, 2, BAP1); // length for remaining part of rid len = _min(len, le16_to_cpu(*(u16*)pBuf)) - 2; if ( len <= 2 ) { printk( KERN_ERR "airo: Rid %x has a length of %d which is too short\n", (int)rid, (int)len ); rc = ERROR; goto done; } // read remainder of the rid if (bap_setup(ai, rid, 2, BAP1) != SUCCESS) { rc = ERROR; goto done; } rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);done: spin_unlock_irqrestore(&ai->bap1_lock, flags); return rc;}/* Note, that we are using BAP1 which is also used by transmit, so * make sure this isnt called when a transmit is happening */static int PC4500_writerid(struct airo_info *ai, u16 rid, const void *pBuf, int len){ u16 status; int flags; int rc = SUCCESS; spin_lock_irqsave(&ai->bap1_lock, flags); // --- first access so that we can write the rid data if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) { rc = status; goto done; } // --- now write the rid data if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) { rc = ERROR; goto done; } bap_write(ai, pBuf, len, BAP1); // ---now commit the rid data rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);done: spin_unlock_irqrestore(&ai->bap1_lock, flags); return rc;}/* Allocates a FID to be used for transmitting packets. We only use one for now. */static u16 transmit_allocate(struct airo_info *ai, int lenPayload){ Cmd cmd; Resp rsp; u16 txFid; u16 txControl; int flags; cmd.cmd = CMD_ALLOCATETX; cmd.parm0 = lenPayload; if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return 0; if ( (rsp.status & 0xFF00) != 0) return 0; /* wait for the allocate event/indication * It makes me kind of nervous that this can just sit here and spin, * but in practice it only loops like four times. */ while ( (IN4500(ai, EVSTAT) & EV_ALLOC) == 0) ; // get the allocated fid and acknowledge txFid = IN4500(ai, TXALLOCFID); OUT4500(ai, EVACK, EV_ALLOC); /* The CARD is pretty cool since it converts the ethernet packet * into 802.11. Also note that we don't release the FID since we * will be using the same one over and over again. */ /* We only have to setup the control once since we are not * releasing the fid. */ txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3 | TXCTL_ETHERNET | TXCTL_NORELEASE); spin_lock_irqsave(&ai->bap1_lock, flags); if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS) return ERROR; bap_write(ai, &txControl, sizeof(txControl), BAP1); spin_unlock_irqrestore(&ai->bap1_lock, flags); return txFid;}/* In general BAP1 is dedicated to transmiting packets. However, since we need a BAP when accessing RIDs, we also use BAP1 for that. Make sure the BAP1 spinlock is held when this is called. */static int transmit_802_3_packet(struct airo_info *ai, u16 txFid, char *pPacket, int len){ u16 payloadLen; Cmd cmd; Resp rsp; if (len < 12) { printk( KERN_WARNING "Short packet %d\n", len ); return ERROR; } // packet is destination[6], source[6], payload[len-12] // write the payload length and dst/src/payload if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR; /* The hardware addresses aren't counted as part of the payload, so * we have to subtract the 12 bytes for the addresses off */ payloadLen = cpu_to_le16(len - 12); bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1); bap_write(ai, (const u16*)pPacket, len, BAP1); // issue the transmit command memset( &cmd, 0, sizeof( cmd ) ); cmd.cmd = CMD_TRANSMIT; cmd.parm0 = txFid; if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR; if ( (rsp.status & 0xFF00) != 0) return ERROR; return SUCCESS;}/* * This is the proc_fs routines. It is a bit messier than I would * like! Feel free to clean it up! *//* * Unfortunately sometime between 2.0 and 2.2 the proc interface changed... * Unfortunately I dont know when it was... * Im guessing it is sometime around 0x20155... Anybody know? */#if (LINUX_VERSION_CODE > 0x20155)static ssize_t proc_read( struct file *file, char *buffer, size_t len, loff_t *offset);static ssize_t proc_write( struct file *file, const char *buffer, size_t len, loff_t *offset );static int proc_close( struct inode *inode, struct file *file );#elsestatic int proc_read( struct inode *inode, struct file *file, char *buffer, int len );static int proc_write( struct inode *inode, struct file *file, const char *buffer, int len );static void proc_close( struct inode *inode, struct file *file );#endifstatic int proc_stats_open( struct inode *inode, struct file *file );static int proc_statsdelta_open( struct inode *inode, struct file *file );static int proc_status_open( struct inode *inode, struct file *file );static int proc_SSID_open( struct inode *inode, struct file *file );static int proc_APList_open( struct inode *inode, struct file *file );static int proc_config_open( struct inode *inode, struct file *file );static int proc_wepkey_open( struct inode *inode, struct file *file );static struct file_operations proc_statsdelta_ops = { read: proc_read, open: proc_statsdelta_open, release: proc_close};static struct file_operations proc_stats_ops = { read: proc_read, open: proc_stats_open, release: proc_close};static struct file_operations proc_status_ops = { read: proc_read, open: proc_status_open, release: proc_close};static struct file_operations proc_SSID_ops = { read: proc_read, write: proc_write, open: proc_SSID_open, release: proc_close};static struct file_operations proc_APList_ops = { read: proc_read, write: proc_write, open: proc_APList_open, release: proc_close};static struct file_operations proc_config_ops = { read: proc_read, write: proc_write, open: proc_config_open, release: proc_close};static struct file_operations proc_wepkey_ops = { read: proc_read, write: proc_write, open: proc_wepkey_open, release: proc_close};#if (LINUX_VERSION_CODE < 0x20355)static struct inode_operations proc_inode_statsdelta_ops = { &proc_statsdelta_ops};static struct inode_operations proc_inode_stats_ops = { &proc_stats_ops};static struct inode_operations proc_inode_status_ops = { &proc_status_ops};static struct inode_operations proc_inode_SSID_ops = { &proc_SSID_ops};static struct inode_operations proc_inode_APList_ops = { &proc_APList_ops};static struct inode_operations proc_inode_config_ops = { &proc_config_ops};static struct inode_operations proc_inode_wepkey_ops = { &proc_wepkey_ops};#endif#if ((LINUX_VERSION_CODE > 0x20155) && (LINUX_VERSION_CODE < 0x20311))/* * We need to do reference counting here. When the inode is first used, * this will be called with fill non-zero. When it is released this
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -