/* * This function registers the device and performs all the necessary * initializations. * * The following initialization operations are performed - * - Allocate adapter structure * - Save interface specific operations table in adapter * - Call interface specific initialization routine * - Allocate private structures * - Set default adapter structure parameters * - Initialize locks * * In case of any errors during inittialization, this function also ensures * proper cleanup before exiting.
*/ staticint mwifiex_register(void *card, struct device *dev, conststruct mwifiex_if_ops *if_ops, void **padapter)
{ struct mwifiex_adapter *adapter; int i;
adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL); if (!adapter) return -ENOMEM;
/* Save interface specific operations in adapter */
memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops));
adapter->debug_mask = debug_mask;
/* card specific initialization has been deferred until now .. */ if (adapter->if_ops.init_if) if (adapter->if_ops.init_if(adapter)) goto error;
adapter->priv_num = 0;
for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) { /* Allocate memory for private structure */
adapter->priv[i] =
kzalloc(sizeof(struct mwifiex_private), GFP_KERNEL); if (!adapter->priv[i]) goto error;
error:
mwifiex_dbg(adapter, ERROR, "info: leave mwifiex_register with error\n");
for (i = 0; i < adapter->priv_num; i++)
kfree(adapter->priv[i]);
kfree(adapter);
return -1;
}
/* * This function unregisters the device and performs all the necessary * cleanups. * * The following cleanup operations are performed - * - Free the timers * - Free beacon buffers * - Free private structures * - Free adapter structure
*/ staticint mwifiex_unregister(struct mwifiex_adapter *adapter)
{
s32 i;
if (adapter->if_ops.cleanup_if)
adapter->if_ops.cleanup_if(adapter);
timer_shutdown_sync(&adapter->cmd_timer);
/* Free private structures */ for (i = 0; i < adapter->priv_num; i++) {
mwifiex_free_curr_bcn(adapter->priv[i]);
kfree(adapter->priv[i]);
}
if (adapter->nd_info) { for (i = 0 ; i < adapter->nd_info->n_matches ; i++)
kfree(adapter->nd_info->matches[i]);
kfree(adapter->nd_info);
adapter->nd_info = NULL;
}
/* * The main process. * * This function is the main procedure of the driver and handles various driver * operations. It runs in a loop and provides the core functionalities. * * The main responsibilities of this function are - * - Ensure concurrency control * - Handle pending interrupts and call interrupt handlers * - Wake up the card if required * - Handle command responses and call response handlers * - Handle events and call event handlers * - Execute pending commands * - Transmit pending data packets
*/ int mwifiex_main_process(struct mwifiex_adapter *adapter)
{ int ret = 0; unsignedlong flags;
/* Check if already processing */ if (adapter->mwifiex_processing || adapter->main_locked) {
adapter->more_task_flag = true;
spin_unlock_irqrestore(&adapter->main_proc_lock, flags); return 0;
} else {
adapter->mwifiex_processing = true;
spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
}
process_start: do { if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY) break;
/* For non-USB interfaces, If we process interrupts first, it * would increase RX pending even further. Avoid this by * checking if rx_pending has crossed high threshold and * schedule rx work queue and then process interrupts. * For USB interface, there are no interrupts. We already have * HIGH_RX_PENDING check in usb.c
*/ if (atomic_read(&adapter->rx_pending) >= HIGH_RX_PENDING &&
adapter->iface_type != MWIFIEX_USB) {
adapter->delay_main_work = true;
mwifiex_queue_rx_work(adapter); break;
}
/* Handle pending interrupt if any */ if (adapter->int_status) { if (adapter->hs_activated)
mwifiex_process_hs_config(adapter); if (adapter->if_ops.process_int_status)
adapter->if_ops.process_int_status(adapter);
}
if (adapter->rx_work_enabled && adapter->data_received)
mwifiex_queue_rx_work(adapter);
/* Need to wake up the card ? */ if ((adapter->ps_state == PS_STATE_SLEEP) &&
(adapter->pm_wakeup_card_req &&
!adapter->pm_wakeup_fw_try) &&
(is_command_pending(adapter) ||
!skb_queue_empty(&adapter->tx_data_q) ||
!mwifiex_bypass_txlist_empty(adapter) ||
!mwifiex_wmm_lists_empty(adapter))) {
adapter->pm_wakeup_fw_try = true;
mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3));
adapter->if_ops.wakeup(adapter); continue;
}
if (IS_CARD_RX_RCVD(adapter)) {
adapter->data_received = false;
adapter->pm_wakeup_fw_try = false;
timer_delete(&adapter->wakeup_timer); if (adapter->ps_state == PS_STATE_SLEEP)
adapter->ps_state = PS_STATE_AWAKE;
} else { /* We have tried to wakeup the card already */ if (adapter->pm_wakeup_fw_try) break; if (adapter->ps_state == PS_STATE_PRE_SLEEP)
mwifiex_check_ps_cond(adapter);
if (adapter->ps_state != PS_STATE_AWAKE) break; if (adapter->tx_lock_flag) { if (adapter->iface_type == MWIFIEX_USB) { if (!adapter->usb_mc_setup) break;
} else break;
}
/* Check for event */ if (adapter->event_received) {
adapter->event_received = false;
mwifiex_process_event(adapter);
}
/* Check for Cmd Resp */ if (adapter->cmd_resp_received) {
adapter->cmd_resp_received = false;
mwifiex_process_cmdresp(adapter);
}
/* Check if we need to confirm Sleep Request
received previously */ if (adapter->ps_state == PS_STATE_PRE_SLEEP)
mwifiex_check_ps_cond(adapter);
/* * The ps_state may have been changed during processing of * Sleep Request event.
*/ if ((adapter->ps_state == PS_STATE_SLEEP) ||
(adapter->ps_state == PS_STATE_PRE_SLEEP) ||
(adapter->ps_state == PS_STATE_SLEEP_CFM)) { continue;
}
if (adapter->tx_lock_flag) { if (adapter->iface_type == MWIFIEX_USB) { if (!adapter->usb_mc_setup) continue;
} else continue;
}
if (!adapter->cmd_sent && !adapter->curr_cmd &&
mwifiex_is_send_cmd_allowed
(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) { if (mwifiex_exec_next_cmd(adapter) == -1) {
ret = -1; break;
}
}
/** If USB Multi channel setup ongoing, * wait for ready to tx data.
*/ if (adapter->iface_type == MWIFIEX_USB &&
adapter->usb_mc_setup) continue;
if ((adapter->scan_chan_gap_enabled ||
!adapter->scan_processing) &&
!adapter->data_sent &&
!skb_queue_empty(&adapter->tx_data_q)) { if (adapter->hs_activated_manually) {
mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY),
MWIFIEX_ASYNC_CMD);
adapter->hs_activated_manually = false;
}
mwifiex_process_tx_queue(adapter); if (adapter->hs_activated) {
clear_bit(MWIFIEX_IS_HS_CONFIGURED,
&adapter->work_flags);
mwifiex_hs_activated_event(adapter, false);
}
}
/* * This function frees the adapter structure. * * Additionally, this closes the netlink socket, frees the timers * and private structures.
*/ staticvoid mwifiex_free_adapter(struct mwifiex_adapter *adapter)
{ if (!adapter) {
pr_err("%s: adapter is NULL\n", __func__); return;
}
/* * This function cancels all works in the queue and destroys * the main workqueue.
*/ staticvoid mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter)
{ if (adapter->workqueue) {
destroy_workqueue(adapter->workqueue);
adapter->workqueue = NULL;
}
if (adapter->rx_workqueue) {
destroy_workqueue(adapter->rx_workqueue);
adapter->rx_workqueue = NULL;
}
if (adapter->host_mlme_workqueue) {
destroy_workqueue(adapter->host_mlme_workqueue);
adapter->host_mlme_workqueue = NULL;
}
}
/* * This function gets firmware and initializes it. * * The main initialization steps followed are - * - Download the correct firmware to card * - Issue the init commands to firmware
*/ staticint _mwifiex_fw_dpc(conststruct firmware *firmware, void *context)
{ int ret; char fmt[64]; struct mwifiex_adapter *adapter = context; struct mwifiex_fw_image fw; bool init_failed = false; struct wireless_dev *wdev; struct completion *fw_done = adapter->fw_done;
if (!firmware) {
mwifiex_dbg(adapter, ERROR, "Failed to get firmware %s\n", adapter->fw_name); goto err_dnld_fw;
}
/* * This function gets the firmware and (if called asynchronously) kicks off the * HW init when done.
*/ staticint mwifiex_init_hw_fw(struct mwifiex_adapter *adapter, bool req_fw_nowait)
{ int ret;
/* Override default firmware with manufacturing one if * manufacturing mode is enabled
*/ if (mfg_mode)
strscpy(adapter->fw_name, MFG_FIRMWARE, sizeof(adapter->fw_name));
if (req_fw_nowait) {
ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name,
adapter->dev, GFP_KERNEL, adapter,
mwifiex_fw_dpc);
} else {
ret = request_firmware(&adapter->firmware,
adapter->fw_name,
adapter->dev);
}
if (ntohs(eth_hdr->h_proto) == ETH_P_PAE ||
mwifiex_is_skb_mgmt_frame(skb) ||
(GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA &&
ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
(ntohs(eth_hdr->h_proto) == ETH_P_TDLS))) {
mwifiex_dbg(priv->adapter, DATA, "bypass txqueue; eth type %#x, mgmt %d\n",
ntohs(eth_hdr->h_proto),
mwifiex_is_skb_mgmt_frame(skb)); if (eth_hdr->h_proto == htons(ETH_P_PAE))
mwifiex_dbg(priv->adapter, MSG, "key: send EAPOL to %pM\n",
eth_hdr->h_dest); returntrue;
}
returnfalse;
} /* * Add buffer into wmm tx queue and queue work to transmit it.
*/ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)
{ struct netdev_queue *txq; int index = mwifiex_1d_to_wmm_queue[skb->priority];
/* Record the current time the packet was queued; used to * determine the amount of time the packet was queued in * the driver before it was sent to the firmware. * The delay is then sent along with the packet to the * firmware for aggregate delay calculation for stats and * MSDU lifetime expiry.
*/
__net_timestamp(skb);
if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
priv->bss_type == MWIFIEX_BSS_TYPE_STA &&
!ether_addr_equal_unaligned(priv->cfg_bssid, skb->data)) { if (priv->adapter->auto_tdls && priv->check_tdls_tx)
mwifiex_tdls_check_tx(priv, skb);
}
mwifiex_queue_tx_pkt(priv, skb);
return 0;
}
int mwifiex_set_mac_address(struct mwifiex_private *priv, struct net_device *dev, bool external,
u8 *new_mac)
{ int ret;
u64 mac_addr, old_mac_addr;
void mwifiex_multi_chan_resync(struct mwifiex_adapter *adapter)
{ struct usb_card_rec *card = adapter->card; struct mwifiex_private *priv;
u16 tx_buf_size; int i, ret;
card->mc_resync_flag = true; for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) { if (atomic_read(&card->port[i].tx_data_urb_pending)) {
mwifiex_dbg(adapter, WARN, "pending data urb in sys\n"); return;
}
}
void mwifiex_upload_device_dump(struct mwifiex_adapter *adapter)
{ /* Dump all the memory data into single file, a userspace script will * be used to split all the memory data to multiple files
*/
mwifiex_dbg(adapter, MSG, "== mwifiex dump information to /sys/class/devcoredump start\n");
dev_coredumpv(adapter->dev, adapter->devdump_data, adapter->devdump_len,
GFP_KERNEL);
mwifiex_dbg(adapter, MSG, "== mwifiex dump information to /sys/class/devcoredump end\n");
/* Device dump data will be freed in device coredump release function * after 5 min. Here reset adapter->devdump_data and ->devdump_len * to avoid it been accidentally reused.
*/
adapter->devdump_data = NULL;
adapter->devdump_len = 0;
}
EXPORT_SYMBOL_GPL(mwifiex_upload_device_dump);
/* * This function initializes the private structure parameters. * * The following wait queues are initialized - * - IOCTL wait queue * - Command wait queue * - Statistics wait queue * * ...and the following default parameters are set - * - Current key index : Set to 0 * - Rate index : Set to auto * - Media connected : Set to disconnected * - Adhoc link sensed : Set to false * - Nick name : Set to null * - Number of Tx timeout : Set to 0 * - Device address : Set to current address * - Rx histogram statistc : Set to 0 * * In addition, the CFG80211 work queue is also created.
*/ void mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev)
{
dev->netdev_ops = &mwifiex_netdev_ops;
dev->needs_free_netdev = true; /* Initialize private structure */
priv->current_key_index = 0;
priv->media_connected = false;
memset(priv->mgmt_ie, 0, sizeof(struct mwifiex_ie) * MAX_MGMT_IE_INDEX);
priv->beacon_idx = MWIFIEX_AUTO_IDX_MASK;
priv->proberesp_idx = MWIFIEX_AUTO_IDX_MASK;
priv->assocresp_idx = MWIFIEX_AUTO_IDX_MASK;
priv->gen_idx = MWIFIEX_AUTO_IDX_MASK;
priv->num_tx_timeout = 0; if (is_valid_ether_addr(dev->dev_addr))
ether_addr_copy(priv->curr_addr, dev->dev_addr); else
ether_addr_copy(priv->curr_addr, priv->adapter->perm_addr);
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA ||
GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
priv->hist_data = kmalloc(sizeof(*priv->hist_data), GFP_KERNEL); if (priv->hist_data)
mwifiex_hist_data_reset(priv);
}
}
/* * This function check if command is pending.
*/ int is_command_pending(struct mwifiex_adapter *adapter)
{ int is_cmd_pend_q_empty;
/* This is the host mlme work queue function. * It handles the host mlme operations.
*/ staticvoid mwifiex_host_mlme_work_queue(struct work_struct *work)
{ struct mwifiex_adapter *adapter =
container_of(work, struct mwifiex_adapter, host_mlme_work);
if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags)) return;
/* Check for host mlme disconnection */ if (adapter->host_mlme_link_lost) { if (adapter->priv_link_lost) {
mwifiex_reset_connect_state(adapter->priv_link_lost,
WLAN_REASON_DEAUTH_LEAVING, true);
adapter->priv_link_lost = NULL;
}
adapter->host_mlme_link_lost = false;
}
/* Check for host mlme Assoc Resp */ if (adapter->assoc_resp_received) {
mwifiex_process_assoc_resp(adapter);
adapter->assoc_resp_received = false;
}
}
/* * This is the RX work queue function. * * It handles the RX operations.
*/ staticvoid mwifiex_rx_work_queue(struct work_struct *work)
{ struct mwifiex_adapter *adapter =
container_of(work, struct mwifiex_adapter, rx_work);
if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags)) return;
mwifiex_process_rx(adapter);
}
/* * This is the main work queue function. * * It handles the main process, which in turn handles the complete * driver operations.
*/ staticvoid mwifiex_main_work_queue(struct work_struct *work)
{ struct mwifiex_adapter *adapter =
container_of(work, struct mwifiex_adapter, main_work);
if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags)) return;
mwifiex_main_process(adapter);
}
/* Common teardown code used for both device removal and reset */ staticvoid mwifiex_uninit_sw(struct mwifiex_adapter *adapter)
{ struct mwifiex_private *priv; int i;
/* We can no longer handle interrupts once we start doing the teardown * below.
*/ if (adapter->if_ops.disable_int)
adapter->if_ops.disable_int(adapter);
/* Stop data */ for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i]; if (priv->netdev) {
mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev))
netif_carrier_off(priv->netdev);
netif_device_detach(priv->netdev);
}
}
for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i];
rtnl_lock(); if (priv->netdev &&
priv->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED) { /* * Close the netdev now, because if we do it later, the * netdev notifiers will need to acquire the wiphy lock * again --> deadlock.
*/
dev_close(priv->wdev.netdev);
wiphy_lock(adapter->wiphy);
mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev);
wiphy_unlock(adapter->wiphy);
}
rtnl_unlock();
}
/* * This function can be used for shutting down the adapter SW.
*/ int mwifiex_shutdown_sw(struct mwifiex_adapter *adapter)
{ struct mwifiex_private *priv;
if (!adapter) return 0;
wait_for_completion(adapter->fw_done); /* Caller should ensure we aren't suspending while this happens */
reinit_completion(adapter->fw_done);
/* This function can be used for reinitting the adapter SW. Required * code is extracted from mwifiex_add_card()
*/ int
mwifiex_reinit_sw(struct mwifiex_adapter *adapter)
{ int ret;
mwifiex_init_lock_list(adapter); if (adapter->if_ops.up_dev)
adapter->if_ops.up_dev(adapter);
if (adapter->rx_work_enabled) {
adapter->rx_workqueue = alloc_workqueue("MWIFIEX_RX_WORK_QUEUE",
WQ_HIGHPRI |
WQ_MEM_RECLAIM |
WQ_UNBOUND, 0); if (!adapter->rx_workqueue) goto err_kmalloc;
INIT_WORK(&adapter->rx_work, mwifiex_rx_work_queue);
}
if (adapter->host_mlme_enabled) {
adapter->host_mlme_workqueue =
alloc_workqueue("MWIFIEX_HOST_MLME_WORK_QUEUE",
WQ_HIGHPRI |
WQ_MEM_RECLAIM |
WQ_UNBOUND, 0); if (!adapter->host_mlme_workqueue) goto err_kmalloc;
INIT_WORK(&adapter->host_mlme_work,
mwifiex_host_mlme_work_queue);
}
/* Register the device. Fill up the private data structure with * relevant information from the card. Some code extracted from * mwifiex_register_dev()
*/
mwifiex_dbg(adapter, INFO, "%s, mwifiex_init_hw_fw()...\n", __func__);
/* _mwifiex_fw_dpc() does its own cleanup */
ret = _mwifiex_fw_dpc(adapter->firmware, adapter); if (ret) {
pr_err("Failed to bring up adapter: %d\n", ret); return ret;
}
mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
adapter->dt_node = dev->of_node;
adapter->irq_wakeup = irq_of_parse_and_map(adapter->dt_node, 0); if (!adapter->irq_wakeup) {
dev_dbg(dev, "fail to parse irq_wakeup from device tree\n"); goto err_exit;
}
ret = devm_request_irq(dev, adapter->irq_wakeup,
mwifiex_irq_wakeup_handler,
IRQF_TRIGGER_LOW | IRQF_NO_AUTOEN, "wifi_wake", adapter); if (ret) {
dev_err(dev, "Failed to request irq_wakeup %d (%d)\n",
adapter->irq_wakeup, ret); goto err_exit;
}
if (device_init_wakeup(dev, true)) {
dev_err(dev, "fail to init wakeup for mwifiex\n"); goto err_exit;
} return;
err_exit:
adapter->irq_wakeup = -1;
}
/* * This function adds the card. * * This function follows the following major steps to set up the device - * - Initialize software. This includes probing the card, registering * the interface operations table, and allocating/initializing the * adapter structure * - Set up the netlink socket * - Create and start the main work queue * - Register the device * - Initialize firmware and hardware * - Add logical interfaces
*/ int
mwifiex_add_card(void *card, struct completion *fw_done, conststruct mwifiex_if_ops *if_ops, u8 iface_type, struct device *dev)
{ struct mwifiex_adapter *adapter;
/* Register the device. Fill up the private data structure with relevant
information from the card. */ if (adapter->if_ops.register_dev(adapter)) {
pr_err("%s: failed to register mwifiex device\n", __func__); goto err_registerdev;
}
if (adapter->host_mlme_enabled) {
adapter->host_mlme_workqueue =
alloc_workqueue("MWIFIEX_HOST_MLME_WORK_QUEUE",
WQ_HIGHPRI |
WQ_MEM_RECLAIM |
WQ_UNBOUND, 0); if (!adapter->host_mlme_workqueue) goto err_kmalloc;
INIT_WORK(&adapter->host_mlme_work,
mwifiex_host_mlme_work_queue);
}
/* * This function removes the card. * * This function follows the following major steps to remove the device - * - Stop data traffic * - Shutdown firmware * - Remove the logical interfaces * - Terminate the work queue * - Unregister the device * - Free the adapter structure
*/ int mwifiex_remove_card(struct mwifiex_adapter *adapter)
{ if (!adapter) return 0;
if (adapter->is_up)
mwifiex_uninit_sw(adapter);
if (adapter->irq_wakeup >= 0)
device_init_wakeup(adapter->dev, false);
if (adapter->dev)
dev_info(adapter->dev, "%pV", &vaf); else
pr_info("%pV", &vaf);
va_end(args);
}
EXPORT_SYMBOL_GPL(_mwifiex_dbg);
/* * This function initializes the module. * * The debug FS is also initialized if configured.
*/ staticint
mwifiex_init_module(void)
{ #ifdef CONFIG_DEBUG_FS
mwifiex_debugfs_init(); #endif return 0;
}
/* * This function cleans up the module. * * The debug FS is removed if available.
*/ staticvoid
mwifiex_cleanup_module(void)
{ #ifdef CONFIG_DEBUG_FS
mwifiex_debugfs_remove(); #endif
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.