| /** |
| * @file mlan_txrx.c |
| * |
| * @brief This file contains the handling of TX/RX in MLAN |
| * |
| * |
| * Copyright (C) 2009, Marvell International Ltd. |
| * All Rights Reserved |
| * |
| */ |
| |
| /************************************************************* |
| Change Log: |
| 05/11/2009: initial version |
| ************************************************************/ |
| |
| #include "mlan.h" |
| #include "mlan_join.h" |
| #include "mlan_util.h" |
| #include "mlan_fw.h" |
| #include "mlan_main.h" |
| #include "mlan_wmm.h" |
| #include "mlan_sdio.h" |
| |
| /******************************************************** |
| Local Variables |
| ********************************************************/ |
| |
| /******************************************************** |
| Global Variables |
| ********************************************************/ |
| |
| /******************************************************** |
| Local Functions |
| ********************************************************/ |
| |
| /******************************************************** |
| Global Functions |
| ********************************************************/ |
| /** |
| * @brief This function processes the received buffer |
| * |
| * @param pmadapter A pointer to mlan_adapter |
| * @param pmbuf A pointer to the received buffer |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status |
| wlan_handle_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| pmlan_private priv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY); |
| t_u32 bss_num = 0; |
| RxPD *prx_pd; |
| |
| ENTER(); |
| |
| prx_pd = (RxPD *) (pmbuf->pbuf + pmbuf->data_offset); |
| /* Get the BSS number from RxPD, get corresponding priv */ |
| bss_num = prx_pd->bss_num & (MLAN_MAX_BSS_NUM - 1); |
| priv = pmadapter->priv[bss_num]; |
| if (!priv) { |
| bss_num = 0; |
| priv = wlan_get_priv(pmadapter, MLAN_BSS_TYPE_ANY); |
| } |
| pmbuf->bss_num = bss_num; |
| ret = priv->ops.process_rx_packet(pmadapter, pmbuf); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief This function queues the packet received from |
| * kernel/upper layer and wake up the main thread to handle it. |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pmbuf A pointer to mlan_buffer includes TX packet |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status |
| wlan_tx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| HEXDUMP("TX Data", pmbuf->pbuf + pmbuf->data_offset, |
| MIN(pmbuf->data_len, 100)); |
| |
| wlan_wmm_add_buf_txqueue(pmadapter, pmbuf); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief This function checks the conditions and sends packet to device |
| * |
| * @param priv A pointer to mlan_private structure |
| * @param pmbuf A pointer to the mlan_buffer for process |
| * @param tx_param A pointer to mlan_tx_param structure |
| * |
| * @return mlan_status |
| */ |
| mlan_status |
| wlan_process_tx(pmlan_private priv, pmlan_buffer pmbuf, |
| mlan_tx_param * tx_param) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| pmlan_adapter pmadapter = priv->adapter; |
| t_u8 *head_ptr = MNULL; |
| t_u32 sec, usec; |
| |
| ENTER(); |
| |
| head_ptr = (t_u8 *) priv->ops.process_txpd(priv, pmbuf); |
| if (!head_ptr) { |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, tx_param); |
| done: |
| switch (ret) { |
| case MLAN_STATUS_RESOURCE: |
| PRINTM(MDATA, "MLAN_STATUS_RESOURCE is returned\n"); |
| break; |
| case MLAN_STATUS_FAILURE: |
| pmadapter->data_sent = MFALSE; |
| PRINTM(MERROR, "Error: moal_write_data_async failed: 0x%X\n", ret); |
| pmadapter->dbg.num_tx_host_to_card_failure++; |
| wlan_write_data_complete(pmadapter, pmbuf, ret); |
| break; |
| case MLAN_STATUS_PENDING: |
| pmadapter->data_sent = MFALSE; |
| break; |
| case MLAN_STATUS_SUCCESS: |
| wlan_write_data_complete(pmadapter, pmbuf, ret); |
| break; |
| default: |
| break; |
| } |
| |
| if ((ret == MLAN_STATUS_SUCCESS) || (ret == MLAN_STATUS_PENDING)) { |
| pmadapter->callbacks.moal_get_system_time(&sec, &usec); |
| PRINTM(MDATA, "%lu.%lu : Data => FW\n", sec, usec); |
| |
| DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + INTF_HEADER_LEN, |
| MIN(pmbuf->data_len + sizeof(TxPD), MAX_DATA_DUMP_LEN)); |
| } |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Packet send completion handling |
| * |
| * @param pmadapter A pointer to mlan_adapter structure |
| * @param pmbuf A pointer to mlan_buffer structure |
| * @param status Callback status |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status |
| wlan_write_data_complete(IN pmlan_adapter pmadapter, |
| IN pmlan_buffer pmbuf, IN mlan_status status) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| pmlan_callbacks pcb; |
| |
| ENTER(); |
| |
| ASSERT(pmadapter && pmbuf); |
| |
| pcb = &pmadapter->callbacks; |
| if (pmbuf->buf_type == MLAN_BUF_TYPE_DATA) { |
| PRINTM(MDATA, "wlan_write_data_complete: DATA\n"); |
| |
| if (!pmbuf->pdesc) { |
| /* pmbuf was allocated by MLAN */ |
| wlan_free_mlan_buffer(&pmadapter->callbacks, pmbuf); |
| } else { |
| /* pmbuf was allocated by MOAL */ |
| pcb->moal_send_packet_complete(pmadapter->pmoal_handle, |
| pmbuf, status); |
| } |
| } |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Packet receive completion callback handler |
| * |
| * @param pmlan_adapter A pointer to mlan_adapter structure |
| * @param pmbuf A pointer to mlan_buffer structure |
| * @param status Callback status |
| * |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| mlan_status |
| wlan_recv_packet_complete(IN t_void * pmlan_adapter, |
| IN pmlan_buffer pmbuf, IN mlan_status status) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter; |
| pmlan_private pmp; |
| pmlan_callbacks pcb; |
| pmlan_buffer pmbuf_parent; |
| |
| ENTER(); |
| ASSERT(pmlan_adapter && pmbuf); |
| |
| pcb = &pmadapter->callbacks; |
| |
| ASSERT(pmbuf->bss_num < MLAN_MAX_BSS_NUM); |
| |
| pmp = pmadapter->priv[pmbuf->bss_num]; |
| |
| if (pmbuf->pparent) { |
| pmbuf_parent = pmbuf->pparent; |
| |
| pmadapter->callbacks.moal_spin_lock(pmp->rx_pkt_lock); |
| --pmbuf_parent->use_count; |
| if (!pmbuf_parent->use_count) { |
| pmadapter->callbacks.moal_spin_unlock(pmp->rx_pkt_lock); |
| pcb->moal_recv_complete(pmadapter->pmoal_handle, |
| pmbuf_parent, pmadapter->ioport, status); |
| } else { |
| pmadapter->callbacks.moal_spin_unlock(pmp->rx_pkt_lock); |
| } |
| |
| pcb->moal_mfree((t_u8 *) pmbuf); |
| } else { |
| pcb->moal_recv_complete(pmadapter->pmoal_handle, pmbuf, |
| pmadapter->ioport, status); |
| } |
| |
| LEAVE(); |
| return ret; |
| } |