/* * We need to differentiate between the surprise and planned removal of the * device because of the following consideration: * * - In case of surprise removal, the hcd already frees up the pending * for the device and hence there is no need to unregister the function * driver inorder to get these requests. For planned removal, the function * driver has to explicitly unregister itself to have the hcd return all the * pending requests before the data structures for the devices are freed up. * Note that as per the current implementation, the function driver will * end up releasing all the devices since there is no API to selectively * release a particular device. * * - Certain commands issued to the target can be skipped for surprise * removal since they will anyway not go through. */ void ath6kl_destroy(struct net_device *dev, unsigned int unregister) { struct ath6kl *ar; if (!dev || !ath6kl_priv(dev)) { ath6kl_err("failed to get device structure\n"); return; } ar = ath6kl_priv(dev); destroy_workqueue(ar->ath6kl_wq); if (ar->htc_target) htc_cleanup(ar->htc_target); aggr_module_destroy(ar->aggr_cntxt); ath6kl_cookie_cleanup(ar); ath6kl_cleanup_amsdu_rxbufs(ar); ath6kl_bmi_cleanup(ar); if (unregister && test_bit(NETDEV_REGISTERED, &ar->flag)) { unregister_netdev(dev); clear_bit(NETDEV_REGISTERED, &ar->flag); } free_netdev(dev); ath6kl_cfg80211_deinit(ar); }
void htc_destroy(HTC_HANDLE HTCHandle) { HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+htc_destroy .. Destroying :0x%p\n", target)); hif_stop(htc_get_hif_device(HTCHandle)); if (target) htc_cleanup(target); AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_destroy\n")); }
int ath6kl_core_init(struct ath6kl *ar) { int ret = 0; struct ath6kl_bmi_target_info targ_info; ar->ath6kl_wq = create_singlethread_workqueue("ath6kl"); if (!ar->ath6kl_wq) return -ENOMEM; ret = ath6kl_bmi_init(ar); if (ret) goto err_wq; ret = ath6kl_bmi_get_target_info(ar, &targ_info); if (ret) goto err_bmi_cleanup; ar->version.target_ver = le32_to_cpu(targ_info.version); ar->target_type = le32_to_cpu(targ_info.type); ar->wdev->wiphy->hw_version = le32_to_cpu(targ_info.version); ret = ath6kl_configure_target(ar); if (ret) goto err_bmi_cleanup; ar->htc_target = htc_create(ar); if (!ar->htc_target) { ret = -ENOMEM; goto err_bmi_cleanup; } ar->aggr_cntxt = aggr_init(ar->net_dev); if (!ar->aggr_cntxt) { ath6kl_err("failed to initialize aggr\n"); ret = -ENOMEM; goto err_htc_cleanup; } ret = ath6kl_init_upload(ar); if (ret) goto err_htc_cleanup; ret = ath6kl_init(ar->net_dev); if (ret) goto err_htc_cleanup; /* This runs the init function if registered */ ret = register_netdev(ar->net_dev); if (ret) { ath6kl_err("register_netdev failed\n"); ath6kl_destroy(ar->net_dev, 0); return ret; } set_bit(NETDEV_REGISTERED, &ar->flag); ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", __func__, ar->net_dev->name, ar->net_dev, ar); return ret; err_htc_cleanup: htc_cleanup(ar->htc_target); err_bmi_cleanup: ath6kl_bmi_cleanup(ar); err_wq: destroy_workqueue(ar->ath6kl_wq); return ret; }