?? am930hw.c
字號:
timeout = jiffies + 500; while( read8(hw, hw->cmd + CMD_OFF_CODE) != 0 && read8(hw, hw->cmd + CMD_OFF_STATUS) == 0 && jiffies < timeout ); if ( jiffies >= timeout ) { printk( KERN_DEBUG "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 */ timeout = jiffies + 1500; while ( read8(hw, hw->cmd + CMD_OFF_STATUS) == SUCMD_STAT_IDLE && jiffies < timeout ); /* Did we time out or did the fw finish with something? */ if ( jiffies >= timeout ) { /* 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; printk(KERN_DEBUG "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); printk(KERN_DEBUG "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 ) { DBPRT( DBFWCMD, "mibgetitem(LOC_TX_BUFFER_OFFSET) Failed!\n"); result = 1; } else { /* We've got the MIB, now init. the main queue */ hw->tx_base = hw->tx_tail; curr_off = hw->tx_base; memset( &ds.desc, 0, sizeof(am930tx_desc_t)); for ( i = 0; i < AM930_NTXDESC; i++) { /* first set the address where the next desc will go */ if ( i < AM930_NTXDESC - 1 ) ds.desc.next = curr_off + sizeof(ds); else ds.desc.next = hw->tx_base; /* 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_status; UINT8 int_mask; UINT8 gcr; /* 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) && (hw->mac->di->state & DEV_PRESENT) && read8(hw, hw->banner) == 'P' && read8(hw, hw->banner+1) == 'C') { /* Make sure we have not overlapped ISR calls */ if ( hw->state & AM930HW_INTOCURRED ) { DBPRT( DBINT, "Overlapping Interrupt detected!\n"); } else { hw->state |= AM930HW_INTOCURRED; /* Lock the int fields */ if ( am930hw_lockint(hw) != 0 ) { DBPRT( DBFWINT, "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)); /* Clear the int bit of the hw->state */ hw->state &= ~AM930HW_INTOCURRED; } else { /* save the int_mask for future restoration */ int_mask = read8( hw, hw->cs + CS_OFF_INT_MASK); write8(hw, hw->cs + CS_OFF_INT_MASK, 0x0f); int_status = read8(hw, hw->cs + CS_OFF_INT_STATUS); write8(hw, hw->cs + CS_OFF_INT_STATUS, 0); am930hw_unlockint(hw);DBPRT(DBFWINT, "Int mask=0x%02x, status=0x%02x\n", int_mask, int_status); /* Handle various int sources */ do { if ( SUCS_INT_IS_SCANCMPLT(int_status) ) { am930hw_onint_scancomplete(hw); } if ( SUCS_INT_IS_TX(int_status) ) { am930hw_onint_tx(hw); } if ( SUCS_INT_IS_RX(int_status) ) { am930hw_onint_rx(hw); } if ( SUCS_INT_IS_CMD(int_status) ) { am930hw_onint_cmdcomplete(hw); } /* Check the int status again, to see if more int events */ /* have occurred */ if ( am930hw_lockint(hw) != 0 ) { DBPRT( DBFWINT, "Unable to lockout f/w, 2nd time\n"); int_status = 0; } else { int_status = read8(hw, hw->cs + CS_OFF_INT_STATUS); if ( int_status != 0 ) /* are we handling again? */ { write8(hw, hw->cs + CS_OFF_INT_STATUS, 0); am930hw_unlockint(hw); } } } while ( int_status != 0 ); /* Clear the ECWAIT bit of GCR (by setting...wierd) */ gcr = inb_p( GCR(hw)); gcr |= BIT3; outb_p( gcr, GCR(hw)); /* Clear the int bit of the hw->state */ hw->state &= ~AM930HW_INTOCURRED; /* set the int_mask to the setting it had on ISR entry */ write8(hw, hw->cs + CS_OFF_INT_MASK, int_mask); /* and unlock! */ am930hw_unlockint(hw); } /* endif lockint */ } /* endif !overlapped */ } /* hw OK, card in slot */ else { DBPRT( DBINT, "ISR called when hw is NULL, hw not CONFIG or " "no card in slot, future ints may be lost!\n"); } return;}/*----------------------------------------------------------------* am930hw_joinbss** I/F function used by mac and mgr to join a specific bss. The* only nod here to the sutro implementation is the sutro_ref_time* argument used by the sutro to update it's internal timers.** returns: AM930HW_SUCCESS or* AM930HW_FAILURE----------------------------------------------------------------*/UINT32 am930hw_joinbss( am930hw_t *hw, UINT32 ch, UINT32 newBSS, UINT48 bssid, char *ssid, UINT32 bcn_int, wlan_bss_ts_t ts, UINT32 sutro_ref_time ){ UINT32 result = AM930HW_SUCCESS; su_mib_mac_mgmt_t mm_mib; DBFENTER; /* retrieve the mib */ if ( am930hw_mibget(hw, SUMIB_MGMT, 0, sizeof(mm_mib), &mm_mib) != AM930HW_SUCCESS ) { result = AM930HW_FAILURE; } else { /* set the bssid */ memcpy( mm_mib.current_bssid, bssid, WLAN_ADDR_LEN ); /* set the ssid */ mm_mib.current_essid[0] = WLAN_IE_SSID; mm_mib.current_essid[1] = strlen(ssid); strcpy( &(mm_mib.current_essid[2]), ssid); /* set the beaconrate */ mm_mib.beacon_period = bcn_int; /* save the mib */ if ( am930hw_mibset(hw, SUMIB_MGMT, 0, sizeof(mm_mib), &mm_mib) != AM930HW_SUCCESS ) { result = AM930HW_FAILURE; } else { DBPRT( DBFWCMD, "Syncing with BSS, ch=%d, newbss=%d\n", (int)ch, (int)newBSS); /* send the sync command */ if ( am930hw_sync( hw, ch, newBSS, (newBSS == 0) ? ts : NULL, sutro_ref_time ) != AM930HW_CMD_SUCCESS ) { result = AM930HW_FAILURE; } } } DBFEXIT; return result;}/*----------------------------------------------------------------* am930hw_onint_cmdcomplete** ISR helper for f/w generated scan complete interrupts** returns: nothing----------------------------------------------------------------*/void am930hw_onint_cmdcomplete( am930hw_t *hw ){ DBPRT( (DBFWINT | DBFWCMD), "cmd complete int, last_cmd= 0x%x\n", hw->last_cmd) hw->last_cmd = 0;}/*----------------------------------------------------------------* am930hw_onint_rx** ISR helper for f/w generated rx complete interrupts** returns: nothing----------------------------------------------------------------*/void am930hw_onint_rx( am930hw_t *hw ){ UINT8 old_state; UINT32 old_head; UINT32 next; UINT32 len; UINT32 data_off; UINT8 state; am930rxfrm_t *frm; DBPRT( (DBFWINT | DBRXPATH), "RX Interrupt.\n"); /* print initial rx_desc *//*#ifdef DBMSG_ENABLED if ( (dbmask & FILEBIT) && (dbmask & 0)) { am930rx_desc_t desc; readcard(hw, hw->rx_head, &desc, sizeof(desc)); am930hw_dbprintRXdesc( &desc ); }#endif*/ /* read the state and next fields from the old head */ state = read8(hw, hw->rx_head + RXD_OFF_STATE); next = am930hw_read_rxnext(hw); while ( !SURXD_ST_IS_FWOWN(state) && SURXD_ST_IS_CONSUMED(state) && !SURXD_ISLAST(next) && ((next&0x0000ffffL) >= hw->rx_base && (next&0x0000ffffL) < (hw->rx_base+hw->rx_len)) ) { /* we've got a valid next ptr, it's time to move on */ old_head = hw->rx_head; old_state = state; hw->rx_head = next & 0x0000ffffL; state = read8( hw, hw->rx_head + RXD_OFF_STATE); /* make sure we own the new descriptor */ if ( SURXD_ST_IS_FWOWN(state) ) { /* we've been handed a desc that's still owned by the f/w */ /* set the head back to the old one, and stop the loop */ hw->rx_head = old_head; break; } else { /* we have a new, valid descriptor...process it */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -