⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 airo.c

📁 pcmcia source code
💻 C
📖 第 1 页 / 共 5 页
字号:
				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 + -