/* * 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); return0;
} 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);
return0;
}
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) return0;
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) return0;
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 return0;
}
/* * 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
}
MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell WiFi-Ex Driver version " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL v2");
Messung V0.5 in Prozent
¤ 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.0.30 Sekunden
(vorverarbeitet am 2026-06-07)
¤
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.
Sekunden
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.