static void __devexit prism2sta_remove_plx(struct pci_dev *pdev) { wlandevice_t *wlandev; hfa384x_t *hw; wlandev = (wlandevice_t *) pci_get_drvdata(pdev); hw = wlandev->priv; p80211netdev_hwremoved(wlandev); /* reset hardware */ prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable); if (pdev->irq) free_irq(pdev->irq, wlandev); unregister_wlandev(wlandev); /* free local stuff */ if (hw) { hfa384x_destroy(hw); kfree(hw); } iounmap((void __iomem *)wlandev->netdev->mem_start); wlan_unsetup(wlandev); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); kfree(wlandev); }
static void prism2_cs_remove(struct pcmcia_device *pdev) { struct wlandevice *wlandev; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) dev_link_t *link = dev_to_instance(pdev); #endif DBFENTER; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) wlandev = pdev->priv; #else wlandev = link->priv; #endif if (wlandev) { p80211netdev_hwremoved(wlandev); unregister_wlandev(wlandev); wlan_unsetup(wlandev); if (wlandev->priv) { hfa384x_t *hw = wlandev->priv; wlandev->priv = NULL; if (hw) { hfa384x_destroy(hw); kfree(hw); } } kfree(wlandev); } #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) pdev->priv = NULL; pcmcia_disable_device(pdev); #else if (link->state & DEV_CONFIG) { if (link->win) pcmcia_release_window(link->win); pcmcia_release_configuration(link->handle); if (link->io.NumPorts1) pcmcia_release_io(link->handle, &link->io); if (link->irq.AssignedIRQ) pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; } link->priv = NULL; kfree(link); #endif DBFEXIT; return; }
/*---------------------------------------------------------------- * prism2sta_detach * * Remove one of the device instances managed by this driver. * Search the list for the given instance, * check our flags for a waiting timer'd release call * call release * Deregister the instance with Card Services * (netdevice) unregister the network device. * unlink the instance from the list * free the link, priv, and priv->priv memory * Note: the dev_list variable is a driver scoped static used to * maintain a list of device instances managed by this * driver. * * Arguments: * link ptr to the instance to detach * * Returns: * nothing * * Side effects: * the link structure is gone, the netdevice is gone * * Call context: * Might be interrupt, don't block. ----------------------------------------------------------------*/ void prism2sta_detach(dev_link_t *link) { dev_link_t **linkp; wlandevice_t *wlandev; hfa384x_t *hw; DBFENTER; /* Locate prev device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) { if (*linkp == link) break; } if (*linkp != NULL) { #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) unsigned long flags; /* Get rid of any timer'd release call */ save_flags(flags); cli(); #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) if (link->state & DEV_RELEASE_PENDING) { del_timer_sync(&link->release); link->state &= ~DEV_RELEASE_PENDING; } #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) restore_flags(flags); #endif /* If link says we're still config'd, call release */ if (link->state & DEV_CONFIG) { prism2sta_release((u_long)link); if (link->state & DEV_STALE_CONFIG) { link->state |= DEV_STALE_LINK; return; } } /* Tell Card Services we're not around any more */ if (link->handle) { pcmcia_deregister_client(link->handle); } /* Unlink device structure, free bits */ *linkp = link->next; if ( link->priv != NULL ) { wlandev = (wlandevice_t*)link->priv; p80211netdev_hwremoved(wlandev); if (link->dev != NULL) { unregister_wlandev(wlandev); } wlan_unsetup(wlandev); if (wlandev->priv) { hw = wlandev->priv; wlandev->priv = NULL; if (hw) { hfa384x_destroy(hw); kfree(hw); } } link->priv = NULL; kfree(wlandev); } kfree(link); } DBFEXIT; return; }
/*---------------------------------------------------------------- * prism2sta_event * * Handler for card services events. * * Arguments: * event The event code * priority hi/low - REMOVAL is the only hi * args ptr to card services struct containing info about * pcmcia status * * Returns: * Zero on success, non-zero otherwise * * Side effects: * * * Call context: * Both interrupt and process thread, depends on the event. ----------------------------------------------------------------*/ static int prism2sta_event ( event_t event, int priority, event_callback_args_t *args) { int result = 0; dev_link_t *link = (dev_link_t *) args->client_data; wlandevice_t *wlandev = (wlandevice_t*)link->priv; hfa384x_t *hw = NULL; DBFENTER; if (wlandev) hw = wlandev->priv; switch (event) { case CS_EVENT_CARD_INSERTION: WLAN_LOG_DEBUG(5,"event is INSERTION\n"); link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; prism2sta_config(link); if (!(link->state & DEV_CONFIG)) { wlandev->netdev->irq = 0; WLAN_LOG_ERROR( "%s: Initialization failed!\n", dev_info); wlandev->msdstate = WLAN_MSD_HWFAIL; break; } /* Fill in the rest of the hw struct */ hw->irq = wlandev->netdev->irq; hw->iobase = wlandev->netdev->base_addr; hw->link = link; if (prism2_doreset) { result = hfa384x_corereset(hw, prism2_reset_holdtime, prism2_reset_settletime, 0); if ( result ) { WLAN_LOG_ERROR( "corereset() failed, result=%d.\n", result); wlandev->msdstate = WLAN_MSD_HWFAIL; break; } } #if 0 /* * TODO: test_hostif() not implemented yet. */ result = hfa384x_test_hostif(hw); if (result) { WLAN_LOG_ERROR( "test_hostif() failed, result=%d.\n", result); wlandev->msdstate = WLAN_MSD_HWFAIL; break; } #endif wlandev->msdstate = WLAN_MSD_HWPRESENT; break; case CS_EVENT_CARD_REMOVAL: WLAN_LOG_DEBUG(5,"event is REMOVAL\n"); link->state &= ~DEV_PRESENT; if (wlandev) { p80211netdev_hwremoved(wlandev); } #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) if (link->state & DEV_CONFIG) { link->release.expires = jiffies + (HZ/20); add_timer(&link->release); } #endif break; case CS_EVENT_RESET_REQUEST: WLAN_LOG_DEBUG(5,"event is RESET_REQUEST\n"); WLAN_LOG_NOTICE( "prism2 card reset not supported " "due to post-reset user mode configuration " "requirements.\n"); WLAN_LOG_NOTICE( " From user mode, use " "'cardctl suspend;cardctl resume' " "instead.\n"); break; case CS_EVENT_RESET_PHYSICAL: case CS_EVENT_CARD_RESET: WLAN_LOG_WARNING("Rx'd CS_EVENT_RESET_xxx, should not " "be possible since RESET_REQUEST was denied.\n"); break; case CS_EVENT_PM_SUSPEND: WLAN_LOG_DEBUG(5,"event is SUSPEND\n"); link->state |= DEV_SUSPEND; if (link->state & DEV_CONFIG) { prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable); pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: WLAN_LOG_DEBUG(5,"event is RESUME\n"); link->state &= ~DEV_SUSPEND; if (link->state & DEV_CONFIG) { pcmcia_request_configuration(link->handle, &link->conf); } break; } DBFEXIT; return 0; /* noone else does anthing with the return value */ }
static void prism2sta_disconnect_usb(struct usb_interface *interface) { wlandevice_t *wlandev; wlandev = (wlandevice_t *)usb_get_intfdata(interface); if (wlandev != NULL) { LIST_HEAD(cleanlist); hfa384x_usbctlx_t *ctlx, *temp; unsigned long flags; hfa384x_t *hw = wlandev->priv; if (!hw) goto exit; spin_lock_irqsave(&hw->ctlxq.lock, flags); p80211netdev_hwremoved(wlandev); list_splice_init(&hw->ctlxq.reapable, &cleanlist); list_splice_init(&hw->ctlxq.completing, &cleanlist); list_splice_init(&hw->ctlxq.pending, &cleanlist); list_splice_init(&hw->ctlxq.active, &cleanlist); spin_unlock_irqrestore(&hw->ctlxq.lock, flags); /* There's no hardware to shutdown, but the driver * might have some tasks or tasklets that must be * stopped before we can tear everything down. */ prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable); del_singleshot_timer_sync(&hw->throttle); del_singleshot_timer_sync(&hw->reqtimer); del_singleshot_timer_sync(&hw->resptimer); /* Unlink all the URBs. This "removes the wheels" * from the entire CTLX handling mechanism. */ usb_kill_urb(&hw->rx_urb); usb_kill_urb(&hw->tx_urb); usb_kill_urb(&hw->ctlx_urb); tasklet_kill(&hw->completion_bh); tasklet_kill(&hw->reaper_bh); cancel_work_sync(&hw->link_bh); cancel_work_sync(&hw->commsqual_bh); /* Now we complete any outstanding commands * and tell everyone who is waiting for their * responses that we have shut down. */ list_for_each_entry(ctlx, &cleanlist, list) complete(&ctlx->done); /* Give any outstanding synchronous commands * a chance to complete. All they need to do * is "wake up", so that's easy. * (I'd like a better way to do this, really.) */ msleep(100); /* Now delete the CTLXs, because no-one else can now. */ list_for_each_entry_safe(ctlx, temp, &cleanlist, list) kfree(ctlx); /* Unhook the wlandev */ unregister_wlandev(wlandev); wlan_unsetup(wlandev); usb_put_dev(hw->usb); hfa384x_destroy(hw); kfree(hw); kfree(wlandev); } exit: usb_set_intfdata(interface, NULL); }