📄 hfa384x.c
字号:
/*----------------------------------------------------------------* hfa384x_cmd_aux_enable** Goes through the process of enabling the auxilary port. This * is necessary prior to raw reads/writes to card data space. * Direct access to the card data space is only used for downloading* code and debugging.* Note that a call to this function is required before attempting* a download.** Arguments:* hw device structure** Returns: * 0 success* >0 f/w reported failure - f/w status code* <0 driver reported error (timeout)** Side effects:** Call context:* process thread ----------------------------------------------------------------*/int hfa384x_cmd_aux_enable(hfa384x_t *hw, int force){ int result = -ETIMEDOUT; unsigned long flags; UINT32 retries_remaining; UINT16 reg; UINT auxen_mirror = hw->auxen; DBFENTER; /* Check for existing enable */ if ( hw->auxen ) { hw->auxen++; return 0; } /* acquire the lock */ spin_lock_irqsave( &(hw->cmdlock), flags); /* wait for cmd register busy bit to clear */ retries_remaining = 100000; do { reg = hfa384x_getreg(hw, HFA384x_CMD); udelay(10); } while (HFA384x_CMD_ISBUSY(reg) && --retries_remaining); if (retries_remaining != 0) { /* busy bit clear, it's OK to write to ParamX regs */ hfa384x_setreg(hw, HFA384x_AUXPW0, HFA384x_PARAM0); hfa384x_setreg(hw, HFA384x_AUXPW1, HFA384x_PARAM1); hfa384x_setreg(hw, HFA384x_AUXPW2, HFA384x_PARAM2); /* Set the aux enable in the Control register */ hfa384x_setreg(hw, HFA384x_CONTROL_AUX_DOENABLE, HFA384x_CONTROL); /* Now wait for completion */ retries_remaining = 100000; do { reg = hfa384x_getreg(hw, HFA384x_CONTROL); udelay(10); } while ( ((reg & (BIT14|BIT15)) != HFA384x_CONTROL_AUX_ISENABLED) && --retries_remaining ); if (retries_remaining != 0) { result = 0; hw->auxen++; } } /* Force it enabled even if the command failed, if told.. */ if ((hw->auxen == auxen_mirror) && force) hw->auxen++; spin_unlock_irqrestore( &(hw->cmdlock), flags); DBFEXIT; return result;}/*----------------------------------------------------------------* hfa384x_cmd_aux_disable** Goes through the process of disabling the auxilary port * enabled with aux_enable().** Arguments:* hw device structure** Returns: * 0 success* >0 f/w reported failure - f/w status code* <0 driver reported error (timeout)** Side effects:** Call context:* process thread ----------------------------------------------------------------*/int hfa384x_cmd_aux_disable(hfa384x_t *hw){ int result = -ETIMEDOUT; unsigned long timeout; UINT16 reg = 0; DBFENTER; /* See if there's more than one enable */ if (hw->auxen) hw->auxen--; if (hw->auxen) return 0; /* Clear the aux enable in the Control register */ hfa384x_setreg(hw, 0, HFA384x_PARAM0); hfa384x_setreg(hw, 0, HFA384x_PARAM1); hfa384x_setreg(hw, 0, HFA384x_PARAM2); hfa384x_setreg(hw, HFA384x_CONTROL_AUX_DODISABLE, HFA384x_CONTROL); /* Now wait for completion */ timeout = jiffies + 1*HZ; reg = hfa384x_getreg(hw, HFA384x_CONTROL); while ( ((reg & (BIT14|BIT15)) != HFA384x_CONTROL_AUX_ISDISABLED) && time_before(jiffies,timeout) ){ udelay(10); reg = hfa384x_getreg(hw, HFA384x_CONTROL); } if ((reg & (BIT14|BIT15)) == HFA384x_CONTROL_AUX_ISDISABLED ) { result = 0; } DBFEXIT; return result;}/*----------------------------------------------------------------* hfa384x_drvr_low_level** Write test commands to the card. Some test commands don't make* sense without prior set-up. For example, continous TX isn't very* useful until you set the channel. That functionality should be** Side effects:** Call context:* process thread * -----------------------------------------------------------------*/int hfa384x_drvr_low_level(hfa384x_t *hw, hfa384x_metacmd_t *cmd){ int result = 0; DBFENTER; /* Do i need a host2hfa... conversion ? */#if 0 printk(KERN_INFO "%#x %#x %#x %#x\n", cmd->cmd, cmd->parm0, cmd->parm1, cmd->parm2);#endif spin_lock_bh(&hw->cmdlock); result = hfa384x_docmd_wait(hw, cmd); spin_unlock_bh(&hw->cmdlock); DBFEXIT; return result;}/* TODO: determine if these will ever be needed */#if 0int hfa384x_cmd_readmif(hfa384x_t *hw){ DBFENTER; DBFEXIT; return 0;}int hfa384x_cmd_writemif(hfa384x_t *hw){ DBFENTER; DBFEXIT; return 0;}#endif/*----------------------------------------------------------------* hfa384x_drvr_mmi_read** Read mmi registers. mmi is intersil-speak for the baseband* processor registers.** Arguments:* hw device structure* register The test register to be accessed (must be even #).** Returns:* 0 success* >0 f/w reported error - f/w status code* <0 driver reported error** Side effects:** Call context:* process thread----------------------------------------------------------------*/int hfa384x_drvr_mmi_read(hfa384x_t *hw, UINT32 addr, UINT32 *resp){ int result = 0; hfa384x_metacmd_t cmd; DBFENTER; cmd.cmd = (UINT16) 0x30; cmd.parm0 = (UINT16) addr; cmd.parm1 = 0; cmd.parm2 = 0; /* Do i need a host2hfa... conversion ? */ spin_lock_bh(&hw->cmdlock); result = hfa384x_docmd_wait(hw, &cmd); spin_unlock_bh(&hw->cmdlock); *resp = (UINT32) cmd.result.resp0; DBFEXIT; return result;}/*----------------------------------------------------------------* hfa384x_drvr_mmi_write** Read mmi registers. mmi is intersil-speak for the baseband* processor registers.** Arguments:* hw device structure* addr The test register to be accessed (must be even #).* data The data value to write to the register.** Returns:* 0 success* >0 f/w reported error - f/w status code* <0 driver reported error** Side effects:** Call context:* process thread----------------------------------------------------------------*/inthfa384x_drvr_mmi_write(hfa384x_t *hw, UINT32 addr, UINT32 data){ int result = 0; hfa384x_metacmd_t cmd; DBFENTER; cmd.cmd = (UINT16) 0x31; cmd.parm0 = (UINT16) addr; cmd.parm1 = (UINT16) data; cmd.parm2 = 0; WLAN_LOG_DEBUG(1,"mmi write : addr = 0x%08x\n", addr); WLAN_LOG_DEBUG(1,"mmi write : data = 0x%08x\n", data); /* Do i need a host2hfa... conversion ? */ spin_lock_bh(&hw->cmdlock); result = hfa384x_docmd_wait(hw, &cmd); spin_unlock_bh(&hw->cmdlock); DBFEXIT; return result;}/* TODO: determine if these will ever be needed */#if 0int hfa384x_cmd_readmif(hfa384x_t *hw){ DBFENTER; DBFEXIT; return 0;}int hfa384x_cmd_writemif(hfa384x_t *hw){ DBFENTER; DBFEXIT; return 0;}#endif/*----------------------------------------------------------------* hfa384x_copy_from_bap** Copies a collection of bytes from the MAC controller memory via* one set of BAP registers.** Arguments:* hw device structure* bap [0|1] which BAP to use* id FID or RID, destined for the select register (host order)* offset An _even_ offset into the buffer for the given* FID/RID. We haven't the means to validate this,* so be careful. (host order)* buf ptr to array of bytes* len length of data to transfer in bytes** Returns: * 0 success* >0 f/w reported failure - value of offset reg.* <0 driver reported error (timeout|bad arg)** Side effects:** Call context:* process thread* interrupt----------------------------------------------------------------*/int hfa384x_copy_from_bap(hfa384x_t *hw, UINT16 bap, UINT16 id, UINT16 offset, void *buf, UINT len){ int result = 0; unsigned long flags = 0; UINT8 *d = (UINT8*)buf; UINT selectreg; UINT offsetreg; UINT datareg; UINT i; UINT16 reg = 0; DBFENTER; /* Validate bap, offset, buf, and len */ if ( (bap > 1) || (offset > HFA384x_BAP_OFFSET_MAX) || (offset % 2) || (buf == NULL) || (len > HFA384x_BAP_DATALEN_MAX) ){ result = -EINVAL; } else { selectreg = (bap == 1) ? HFA384x_SELECT1 : HFA384x_SELECT0 ; offsetreg = (bap == 1) ? HFA384x_OFFSET1 : HFA384x_OFFSET0 ; datareg = (bap == 1) ? HFA384x_DATA1 : HFA384x_DATA0 ; /* Obtain lock */ spin_lock_irqsave( &(hw->baplock), flags); /* Write id to select reg */ hfa384x_setreg(hw, id, selectreg); /* Write offset to offset reg */ hfa384x_setreg(hw, offset, offsetreg); /* Wait for offset[busy] to clear (see BAP_TIMEOUT) */ i = 0; do { reg = hfa384x_getreg(hw, offsetreg); if ( i > 0 ) udelay(10); i++; } while ( i < prism2_bap_timeout && HFA384x_OFFSET_ISBUSY(reg));#if (WLAN_HOSTIF != WLAN_PCI) /* Release lock */ spin_unlock_irqrestore( &(hw->baplock), flags);#endif if ( HFA384x_OFFSET_ISBUSY(reg) ){ /* If timeout, return -ETIMEDOUT */ result = reg; } else if ( HFA384x_OFFSET_ISERR(reg) ){ /* If offset[err] == 1, return -EINVAL */ result = reg; } else { /* Read even(len) buf contents from data reg */ for ( i = 0; i < (len & 0xfffe); i+=2 ) { *(UINT16*)(&(d[i])) = hfa384x_getreg_noswap(hw, datareg); } /* If len odd, handle last byte */ if ( len % 2 ){ reg = hfa384x_getreg_noswap(hw, datareg); d[len-1] = ((UINT8*)(®))[0]; } } /* According to Intersil errata dated 9/16/02: "In PRISM PCI MAC host interface, if both BAPs are concurrently requesing memory access, both will accept the Ack. There is no firmware workaround possible. To prevent BAP access failures or hang conditions the host MUST NOT access both BAPs in sucession unless at least 5us elapses between accesses. The safest choice is to USE ONLY ONE BAP for all data movement operations." What this means: We have to serialize ALL BAP accesses, and furthermore, add a 5us delay after access if we're using a PCI platform. Unfortunately, this means we have to lock out interrupts througout the entire BAP copy. It remains to be seen if "BAP access" means "BAP setup" or the more literal definition of "copying data back and forth" I'm erring for the latter, safer definition. -- SLP. */#if (WLAN_HOSTIF == WLAN_PCI) udelay(5); /* Release lock */ spin_unlock_irqrestore( &(hw->baplock), flags);#endif } if (result) { WLAN_LOG_DEBUG(1, "copy_from_bap(0x%04x, 0, %d) failed, result=0x%x\n", reg, len, result); } DBFEXIT; return result;}/*----------------------------------------------------------------* hfa384x_copy_to_bap** Copies a collection of bytes to the MAC controller memory via* one set of BAP registers.** Arguments:* hw device structure* bap [0|1] which BAP to use* id FID or RID, destined for the select register (host order)* offset An _even_ offset into the buffer for the given* FID/RID. We haven't the means to validate this,* so be careful. (host order)* buf ptr to array of bytes* len length of data to transfer (in bytes)** Returns: * 0 success* >0 f/w reported failure - value of offset reg.* <0 driver reported error (timeout|bad arg)** Side effects:** Call context:* process thread* interrupt----------------------------------------------------------------*/int hfa384x_copy_to_bap(hfa384x_t *hw, UINT16 bap, UINT16 id, UINT16 offset, void *buf, UINT len){ return hfa384x_copy_to_bap4(hw, bap, id, offset, buf, len, NULL, 0, NULL, 0, NULL, 0);}int hfa384x_copy_to_bap4(hfa384x_t *hw, UINT16 bap, UINT16 id, UINT16 offset, void *buf, UINT len1, void* buf2, UINT len2, void *buf3, UINT len3, void *buf4, UINT len4){ int result = 0; unsigned long flags = 0; UINT8 *d; UINT selectreg; UINT offsetreg; UINT datareg; UINT i; UINT16 reg; DBFENTER;// printk(KERN_DEBUG "ctb1 %d id %04x o %d %d %d %d %d\n", bap, id, offset, len1, len2, len3, len4); /* Validate bap, offset, buf, and len */ if ( (bap > 1) || (offset > HFA384x_BAP_OFFSET_MAX) || (offset % 2) || (buf == NULL) || (len1+len2+len3+l
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -