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

📄 am930hw.c

📁 Linux Wireless LAN Project 的目标是开发一个完整的
💻 C
📖 第 1 页 / 共 5 页
字号:
				/* clear the MIB counter items */				memset( &mib_stats, 0, sizeof(mib_stats));				am930hw_mibset( hw, SUMIB_STAT, 0, 							sizeof(mib_stats), &mib_stats);				/* increase the tx buffer size */				am930hw_mibget( hw, SUMIB_LOCAL, 0, 							sizeof(su_mib_local_t), &mib);				WLAN_LOG_DEBUG2(1, "default f/w tx.off=0x%04lx tx.len=0x%04lx\n", 					amd2host32(mib.tx_buffer_offset), amd2host32(mib.tx_buffer_size));				WLAN_LOG_DEBUG2(1, "default f/w rx.off=0x%04lx rx.len=0x%04lx\n", 					amd2host32(mib.rx_buffer_offset), amd2host32(mib.rx_buffer_size));				mib.tx_buffer_size = 					host2amd32(AM930_NTXDESC * AM930_TXSLOT_LEN);				rx_buffer_top = 					amd2host32(mib.rx_buffer_offset) +					amd2host32(mib.rx_buffer_size);				mib.rx_buffer_offset = 					host2amd32(						amd2host32(mib.tx_buffer_offset) + 						amd2host32(mib.tx_buffer_size) );				mib.rx_buffer_size = 					host2amd32(						rx_buffer_top - 						amd2host32(mib.rx_buffer_offset));				WLAN_LOG_DEBUG2(1, "f/w tx.off=0x%04lx tx.len=0x%04lx\n", 					amd2host32(mib.tx_buffer_offset), amd2host32(mib.tx_buffer_size));				WLAN_LOG_DEBUG2(1, "f/w rx.off=0x%04lx rx.len=0x%04lx\n", 					amd2host32(mib.rx_buffer_offset), amd2host32(mib.rx_buffer_size));				am930hw_mibset( hw, SUMIB_LOCAL, 0, 							sizeof(su_mib_local_t), &mib);				/* If we're an AP, set some extra items */				if (am930_isap)  /* can't do this, it isn't set yet hw->mac->mode == AM930_MACMODE_ESS_AP) */				{					/* set the AP mib */					am930hw_mibsetitem( hw, LOC_NETWORK_MODE, &one, MI_SZ(LOC_NETWORK_MODE));					/* set the AP mib */					am930hw_mibsetitem( hw, LOC_ACTING_AS_AP, &one, MI_SZ(LOC_ACTING_AS_AP));					/* Set the driver state */					if (hw->mac->mode == AM930_MACMODE_ESS_AP)					{						am930hw_stateset( hw, SUCS_DS_AP_NO_ASSOC);#if (WLAN_OS == WLAN_LWOS)//						LED_Blink( WLAN_HLED_LINK, LED_OFF);#endif					}				}				/* clear the VBM area */				memsetcard( hw, hw->vbm, 0x00, 0x100);				/* Get the rx buffer loc and size for sanity checking in */				/*  onint_rx */				am930hw_mibget( hw, SUMIB_LOCAL, 0, 						sizeof(su_mib_local_t), &mib);				hw->rx_base = amd2host32(mib.rx_buffer_offset);				hw->rx_len  = amd2host32(mib.rx_buffer_size);				/* Save our MAC address */				am930hw_mibgetitem( hw, ADDR_MAC_ADDR, 					hw->addr, MI_SZ(ADDR_MAC_ADDR) );				/* Set the f/w interrupt mask and status */				am930hw_getset_int( hw, SU_SET_INTMASK1 | SU_SET_INTSTATUS1, 					SUCS_INT_WAKEUP |					SUCS_INT_CFPEND |					SUCS_INT_DTIMTX |					SUCS_INT_CFPSTART |					SUCS_INT_MASK_CMD,					0x00 );				am930hw_getset_int( hw, SU_SET_INTMASK2 | SU_SET_INTSTATUS2, 					0x00, 0x00 );								/* Enable Core Generated Interrupts and clear any pending */				reg = inb_p( GCR(hw) );				reg |= BIT1 | BIT3;				outb_p( reg, GCR(hw) );			}		}	}	DBFEXIT;    return hw;} /*----------------------------------------------------------------*	am930hw_destruct**	returns: nothing----------------------------------------------------------------*/void am930hw_destruct(am930hw_t *hw){	DBFENTER;#if (WLAN_OS == WLAN_LINUX_KERNEL)	kfree_s( hw, sizeof(am930hw_t));#elif (WLAN_OS == WLAN_LWOS)#else	#error "No WLAN_OS match!"#endif	DBFEXIT;	return;}/*----------------------------------------------------------------*	am930hw_fw_cmd**	This is a helper function used to send commands to the*	firmware. It copies its arguments to the command block*	and then sets the command. After setting the command, we then*	wait for the command to complete. The wait includes a timeout*	and if the command times out, that status is returned.*	Otherwise we return the firmware indicated status. If the*	firmware status is OK and if needed, the command parms are*	copied to the buffer space provided by the caller.**	Argument notes:*		the ABS of the parmsize argument provides the number of *		bytes to copy to the command parm area, and if the parm*		is < 0 then after the command completes, we copy that*		many bytes back from the command parm area as well.**	returns: an am930cmd_result_t structure, which should be *			four bytes long and can be played with like an int.----------------------------------------------------------------*/am930hw_cmd_result_t am930hw_fw_cmd( am930hw_t *hw, UINT8 cmd, void* cmdparms, INT32 parmsize){	am930hw_cmd_result_t	result;	UINT32					timeout;	DBFENTER;	/* clear the result struct */	memset( &result, 0, sizeof(result));	/* wait for the cmd block to be available */#if (WLAN_OS == WLAN_LINUX_KERNEL)	timeout = jiffies + wlan_ms_to_ticks(100);	while(  read8(hw, hw->cmd + CMD_OFF_CODE) != 0 &&			read8(hw, hw->cmd + CMD_OFF_STATUS) == 0 &&			jiffies < timeout );#elif (WLAN_OS == WLAN_LWOS)	timeout = 1000;	while(  read8(hw, hw->cmd + CMD_OFF_CODE) != 0 &&			read8(hw, hw->cmd + CMD_OFF_STATUS) == 0 &&			timeout )	{		udelay(10);		timeout--;	}#else	#error "No WLAN_OS match!"#endif#if (WLAN_OS == WLAN_LINUX_KERNEL)	if ( jiffies >= timeout )#elif (WLAN_OS == WLAN_LWOS)	if ( timeout == 0 )#else	#error "No WLAN_OS match!"#endif	{		WLAN_LOG_WARNING0("Timed out waiting for f/w cmd byte available\n");		result.drvr_status = AM930HW_FWNOTREADY;	}	else	{		/* Make sure the status and code are set properly */		write8(hw, hw->cmd + CMD_OFF_CODE, 0);		write8(hw, hw->cmd + CMD_OFF_STATUS, 0);				/* copy the parms to the command block */		if ( parmsize != 0 )		{			writecard(hw, hw->cmd + CMD_OFF_PARMS, cmdparms, ABS(parmsize));		}		/* Tell the hw object that this cmd is the most recent */		hw->last_cmd = cmd;		/* set the command */		write8(hw, hw->cmd + CMD_OFF_CODE, cmd);		/* Now, wait for the result */#if (WLAN_OS == WLAN_LINUX_KERNEL)		timeout = jiffies + wlan_ms_to_ticks(1500);		while ( read8(hw, hw->cmd + CMD_OFF_STATUS) == SUCMD_STAT_IDLE && 				jiffies < timeout );#elif (WLAN_OS == WLAN_LWOS)		timeout = 1500;		while ( read8(hw, hw->cmd + CMD_OFF_STATUS) == SUCMD_STAT_IDLE && 				timeout )		{			udelay(10);			timeout--;		}#else	#error "No WLAN_OS match!"#endif		/* Did we time out or did the fw finish with something? */#if (WLAN_OS == WLAN_LINUX_KERNEL)		if ( jiffies >= timeout )#elif (WLAN_OS == WLAN_LWOS)		if ( timeout == 0 )#else	#error "No WLAN_OS match!"#endif		{			/* If we timed out, simply set the drvr status and return */			result.fw_status = read8(hw, hw->cmd + CMD_OFF_STATUS);			result.drvr_status = AM930HW_FWCMDTIMEOUT;			WLAN_LOG_WARNING1("We timed out on command: 0x%02x\n", hw->last_cmd);		}		else		{			/* The fw finished with something, what? */			if ( read8(hw, hw->cmd + CMD_OFF_STATUS) != SUCMD_STAT_CMPLT )			{				/* some error occurred, save the result and move on */				result.fw_status = read8(hw, hw->cmd + CMD_OFF_STATUS);				result.fw_err_off = read8(hw, hw->cmd + CMD_OFF_ERR_OFF);				WLAN_LOG_DEBUG1(1,"f/w cmd error, code=0x%x\n", result.fw_status);			}			else			{				/* Everything appears to be OK, now collect any results */				result.drvr_status = 0;				result.fw_status = read8(hw, hw->cmd + CMD_OFF_STATUS);				if ( parmsize < 0 )				{					readcard( hw, hw->cmd + CMD_OFF_PARMS, cmdparms, ABS(parmsize));				}			}			/* clear the cmd and status */			write8(hw, hw->cmd + CMD_OFF_CODE, 0);			write8(hw, hw->cmd + CMD_OFF_STATUS, 0);		}	}	DBFEXIT;	return result;} /*----------------------------------------------------------------*	am930hw_getset_int**	Attempts to access the sutro f/w control structure int_mask or*	int_status field of the given control/status block. It uses the*	lockout_fw and lockout_host fields to block the firmware from*	accessing the mask and status fields while we get or update*	them.**	action values:*		SU_GET_INTMASK1		get the interrupt mask*		SU_SET_INTMASK1		set the interrupt mask*		SU_GET_INTMASK2		get the interrupt mask*		SU_SET_INTMASK2		set the interrupt mask*		SU_GET_INTSTATUS1	get the interrupt status*		SU_GET_INTSTATUS1	get the interrupt status*		SU_SET_INTSTATUS2	set the interrupt status*		SU_SET_INTSTATUS2	set the interrupt status**	The value argument is only used by the SET actions.**	returns: -1 on failure, *			 0 or GET result on success----------------------------------------------------------------*/static UINT16 am930hw_getset_int( am930hw_t *hw, 								int action,								UINT8 mask,								UINT8 status ){	UINT16 result = 0;	DBFENTER;	if ( am930hw_lockint(hw) == 0 )	{		if (action & SU_GET_INTMASK1 )			result = read8(hw, hw->cs + CS_OFF_INT_MASK);		if ( action & SU_SET_INTMASK1 )			write8(hw, hw->cs + CS_OFF_INT_MASK, mask);		if (action & SU_GET_INTMASK2 )			result = read8(hw, hw->cs + CS_OFF_INT_MASK2);		if ( action & SU_SET_INTMASK2 )			write8(hw, hw->cs + CS_OFF_INT_MASK2, mask);		if ( action & SU_GET_INTSTATUS1 )			result = read8(hw, hw->cs + CS_OFF_INT_STATUS);		if ( action & SU_SET_INTSTATUS1 )			write8(hw, hw->cs + CS_OFF_INT_STATUS, status);		if ( action & SU_GET_INTSTATUS2 )			result = read8(hw, hw->cs + CS_OFF_INT_STATUS2);		if ( action & SU_SET_INTSTATUS2 )			write8(hw, hw->cs + CS_OFF_INT_STATUS2, status);		am930hw_unlockint(hw);	}	else	{		result = -1;	}	DBFEXIT;	return result;}/*----------------------------------------------------------------*	am930hw_init_rx_tx**	Performs the second part of the object initialization. We have*	to do this here so that all of the links are in place in the*	other objects. Particularly so that interrupts get routed to*	this object.**	returns: zero on success, non-zero on failure----------------------------------------------------------------*/int am930hw_init_rx_tx( am930hw_t *hw ){	int		result = 0;	DBFENTER;	/* Configure the tx queues */	if ( am930hw_init_tx_queues(hw) != 0 )	{		result = 1;	}	else	{		/* Enable tx */		if ( am930hw_tx_enable(hw) != AM930HW_CMD_SUCCESS )		{			result = 2;		}		else		{			udelay(100);			/* Enable rx */			if ( am930hw_rx_enable(hw) != AM930HW_CMD_SUCCESS )			{				result = 3;			}			else			{				udelay(100);			}		}	}	DBFEXIT;	return result;}/*----------------------------------------------------------------*	am930hw_init_tx_queue**	Initialize the tx queue related data structures and members of*	the hw object.**	NOTE: this function takes care of am930 related queues, NOT*			any of the upper level protocol packet queues.**	returns: nothing----------------------------------------------------------------*/int am930hw_init_tx_queues( am930hw_t *hw){	int					result = 0;	int					i;	UINT32				curr_off;	am930tx_dataslot_t	ds;	DBFENTER;	/* From the MIB, find out where the TX queue is supposed to go */	if ( am930hw_mibgetitem( hw, LOC_TX_BUFFER_OFFSET, 			&(hw->tx_tail), sizeof(hw->tx_tail)) != AM930HW_CMD_SUCCESS )	{		WLAN_LOG_ERROR0("mibgetitem(LOC_TX_BUFFER_OFFSET) Failed!\n");		result = 1;	}	else	{		/* We've got the MIB, now init. the main queue */		hw->tx_tail = amd2host32(hw->tx_tail);		hw->tx_base = hw->tx_tail;		am930hw_mibgetitem( hw, LOC_TX_BUFFER_SIZE, 			&(hw->tx_len), sizeof(hw->tx_len));		hw->tx_len = amd2host32(hw->tx_len);		curr_off = hw->tx_base;		hw->ntxbuf = hw->tx_len / sizeof(am930tx_dataslot_t);		hw->used_txbuf = 0;		WLAN_LOG_INFO1("Allocated %d tx slots\n", hw->ntxbuf);		memset( &ds.desc, 0, sizeof(am930tx_desc_t));		for ( i = 0; i < hw->ntxbuf; i++)		{			/* first set the address where the next desc will go */			ds.desc.next = (i < hw->ntxbuf - 1) ?				host2amd32(curr_off + sizeof(ds)) :				host2amd32(hw->tx_base);			/* set the prev ptr */			ds.desc.prev = (i > 0) ?				host2amd32(curr_off - sizeof(ds)) :				host2amd32(hw->tx_base + (sizeof(ds) * (hw->ntxbuf - 1)));			/* write the descriptor */			writecard( hw, curr_off, &ds.desc, sizeof(ds.desc));			/* update the offset */			curr_off += sizeof(ds);		}	}		DBFEXIT;	return result;}/*----------------------------------------------------------------*	am930hw_ISR**	HW object interrupt service routine. Called when the pcmcia*	circuitry has generated a host interrupt in response to an*	interrupt from supposedly our card.**	returns: nothing----------------------------------------------------------------*/void am930hw_ISR( am930hw_t *hw ){	UINT8	int_status1;	UINT8	int_status2;	UINT8	int_mask1;	UINT8	int_mask2;	UINT8	gcr;	UINT8	handled = 0;	DBFENTER;	/* Make sure the hw object is ready */	/*  - additional checks make sure the H/W is _really_ in the slot */	/*  - sometimes an int reaches here after a card is removed and before */	/*    card services has been notified. (Thanks David) */	if ( (hw != NULL) && 		 (hw->state & AM930HW_CONFIG)#if (WLAN_OS == WLAN_LINUX_KERNEL)#ifdef WLAN_PCMCIA		 && (((dev_link_t*)(hw->mac->di))->state & DEV_PRESENT)		 && read8(hw, hw->banner) == 'P' && read8(hw, hw->banner+1) == 'C'#endif		)#elif (WLAN_OS == WLAN_LWOS)		)#else	#error "No WLAN_OS match!"#endif	{		/* Make sure we have not overlapped ISR calls */		if ( hw->state & AM930HW_INTOCURRED )		{			WLAN_LOG_WARNING0("Overlapping Interrupt detected!\n");		}		else		{			hw->state |= AM930HW_INTOCURRED;			/* Lock the int fields */			if ( am930hw_lockint(hw) != 0 )			{				WLAN_LOG_DEBUG0(2,"Unable to lockout f/w, skip interrupt\n");				/* Clear the ECWAIT bit of GCR (by setting...wierd) */				gcr = inb_p( GCR(hw));				gcr |= BIT3;				outb_p( gcr, GCR(hw));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -