[s3c24xx] Remove 2.6.31 support.
[openwrt/svn-archive/archive.git] / target / linux / s3c24xx / files-2.6.31 / drivers / ar6000 / hif / hif2.c
diff --git a/target/linux/s3c24xx/files-2.6.31/drivers/ar6000/hif/hif2.c b/target/linux/s3c24xx/files-2.6.31/drivers/ar6000/hif/hif2.c
deleted file mode 100644 (file)
index 386d96e..0000000
+++ /dev/null
@@ -1,768 +0,0 @@
-/*
- * hif2.c - HIF layer re-implementation for the Linux SDIO stack
- *
- * Copyright (C) 2008, 2009 by OpenMoko, Inc.
- * Written by Werner Almesberger <werner@openmoko.org>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * Based on:
- *
- * @abstract: HIF layer reference implementation for Atheros SDIO stack
- * @notice: Copyright (c) 2004-2006 Atheros Communications Inc.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/kthread.h>
-#include <linux/list.h>
-#include <linux/wait.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/sdio_ids.h>
-
-#include "athdefs.h"
-#include "a_types.h"
-#include "hif.h"
-
-
-/* @@@ Hack - this wants cleaning up */
-
-#ifdef CONFIG_MACH_NEO1973_GTA02
-
-#include <mach/gta02-pm-wlan.h>
-
-#else /* CONFIG_MACH_NEO1973_GTA02 */
-
-#define        gta02_wlan_query_rfkill_lock()  1
-#define        gta02_wlan_set_rfkill_cb(cb, hif) ((void) cb)
-#define        gta02_wlan_query_rfkill_unlock()
-#define        gta02_wlan_clear_rfkill_cb()
-
-#endif /* !CONFIG_MACH_NEO1973_GTA02 */
-
-
-/*
- * KNOWN BUGS:
- *
- * - HIF_DEVICE_IRQ_ASYNC_SYNC doesn't work yet (gets MMC errors)
- * - latency can reach hundreds of ms, probably because of scheduling delays
- * - packets go through about three queues before finally hitting the network
- */
-
-/*
- * Differences from Atheros' HIFs:
- *
- * - synchronous and asynchronous requests may get reordered with respect to
- *   each other, e.g., if HIFReadWrite returns for an asynchronous request and
- *   then HIFReadWrite is called for a synchronous request, the synchronous
- *   request may be executed before the asynchronous request.
- *
- * - request queue locking seems unnecessarily complex in the Atheros HIFs.
- *
- * - Atheros mask interrupts by calling sdio_claim_irq/sdio_release_irq, which
- *   can cause quite a bit of overhead. This HIF has its own light-weight
- *   interrupt masking.
- *
- * - Atheros call deviceInsertedHandler from a thread spawned off the probe or
- *   device insertion function. The original explanation for the Atheros SDIO
- *   stack said that this is done because a delay is needed to let the chip
- *   complete initialization. There is indeed a one second delay in the thread.
- *
- *   The Atheros Linux SDIO HIF removes the delay and only retains the thread.
- *   Experimentally removing the thread didn't show any conflicts, so let's get
- *   rid of it for good.
- *
- * - The Atheros SDIO stack with Samuel's driver sets SDIO_CCCR_POWER in
- *   SDIO_POWER_EMPC. Atheros' Linux SDIO code apparently doesn't. We don't
- *   either, and this seems to work fine.
- *   @@@ Need to check this with Atheros.
- */
-
-
-#define MBOXES                 4
-
-#define HIF_MBOX_BLOCK_SIZE    128
-#define        HIF_MBOX_BASE_ADDR      0x800
-#define        HIF_MBOX_WIDTH          0x800
-#define        HIF_MBOX_START_ADDR(mbox) \
-    (HIF_MBOX_BASE_ADDR+(mbox)*HIF_MBOX_WIDTH)
-
-
-struct hif_device {
-       void *htc_handle;
-       struct sdio_func *func;
-
-       /*
-        * @@@ our sweet little bit of bogosity - the mechanism that lets us
-        * use the SDIO stack from softirqs. This really wants to use skbs.
-        */
-       struct list_head queue;
-       spinlock_t queue_lock;
-       struct task_struct *io_task;
-       wait_queue_head_t wait;
-
-       /*
-        * activate_lock protects "active" and the activation/deactivation
-        * process itself.
-        *
-        * Relation to other locks: The SDIO function can be claimed while
-        * activate_lock is being held, but trying to acquire activate_lock
-        * while having ownership of the SDIO function could cause a deadlock.
-        */
-       int active;
-       struct mutex activate_lock;
-};
-
-struct hif_request {
-       struct list_head list;
-       struct sdio_func *func;
-       int (*read)(struct sdio_func *func,
-           void *dst, unsigned int addr, int count);
-       int (*write)(struct sdio_func *func,
-           unsigned int addr, void *src, int count);
-       void *buf;
-       unsigned long addr;
-       int len;
-       A_STATUS (*completion)(void *context, A_STATUS status);
-       void *context;
-};
-
-
-static HTC_CALLBACKS htcCallbacks;
-
-/*
- * shutdown_lock prevents recursion through HIFShutDownDevice
- */
-static DEFINE_MUTEX(shutdown_lock);
-
-
-/* ----- Request processing ------------------------------------------------ */
-
-
-static A_STATUS process_request(struct hif_request *req)
-{
-       int ret;
-       A_STATUS status;
-
-       dev_dbg(&req->func->dev, "process_request(req %p)\n", req);
-       sdio_claim_host(req->func);
-       if (req->read) {
-               ret = req->read(req->func, req->buf, req->addr, req->len);
-       } else {
-               ret = req->write(req->func, req->addr, req->buf, req->len);
-       }
-       sdio_release_host(req->func);
-       status = ret ? A_ERROR : A_OK;
-       if (req->completion)
-               req->completion(req->context, status);
-       kfree(req);
-       return status;
-}
-
-
-static void enqueue_request(struct hif_device *hif, struct hif_request *req)
-{
-       unsigned long flags;
-
-       dev_dbg(&req->func->dev, "enqueue_request(req %p)\n", req);
-       spin_lock_irqsave(&hif->queue_lock, flags);
-       list_add_tail(&req->list, &hif->queue);
-       spin_unlock_irqrestore(&hif->queue_lock, flags);
-       wake_up(&hif->wait);
-}
-
-
-static struct hif_request *dequeue_request(struct hif_device *hif)
-{
-       struct hif_request *req;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hif->queue_lock, flags);
-       if (list_empty(&hif->queue))
-               req = NULL;
-       else {
-               req = list_first_entry(&hif->queue,
-                   struct hif_request, list);
-               list_del(&req->list);
-       }
-       spin_unlock_irqrestore(&hif->queue_lock, flags);
-       return req;
-}
-
-
-static void wait_queue_empty(struct hif_device *hif)
-{
-       unsigned long flags;
-       int empty;
-
-       while (1) {
-               spin_lock_irqsave(&hif->queue_lock, flags);
-               empty = list_empty(&hif->queue);
-               spin_unlock_irqrestore(&hif->queue_lock, flags);
-               if (empty)
-                       break;
-               else
-                       yield();
-       }
-}
-
-
-static int io(void *data)
-{
-       struct hif_device *hif = data;
-       struct sched_param param = { .sched_priority = 2 };
-               /* one priority level slower than ksdioirqd (which is at 1) */
-       DEFINE_WAIT(wait);
-       struct hif_request *req;
-
-       sched_setscheduler(current, SCHED_FIFO, &param);
-
-       while (1) {
-               while (1) {
-                       /*
-                        * Since we never use signals here, one might think
-                        * that this ought to be TASK_UNINTERRUPTIBLE. However,
-                        * such a task would increase the load average and,
-                        * worse, it would trigger the softlockup check.
-                        */
-                       prepare_to_wait(&hif->wait, &wait, TASK_INTERRUPTIBLE);
-                       if (kthread_should_stop()) {
-                               finish_wait(&hif->wait, &wait);
-                               return 0;
-                       }
-                       req = dequeue_request(hif);
-                       if (req)
-                               break;
-                       schedule();
-               }
-               finish_wait(&hif->wait, &wait);
-
-               (void) process_request(req);
-       }
-       return 0;
-}
-
-
-A_STATUS HIFReadWrite(HIF_DEVICE *hif, A_UINT32 address, A_UCHAR *buffer,
-    A_UINT32 length, A_UINT32 request, void *context)
-{
-       struct device *dev = HIFGetOSDevice(hif);
-       struct hif_request *req;
-
-       dev_dbg(dev, "HIFReadWrite(device %p, address 0x%x, buffer %p, "
-           "length %d, request 0x%x, context %p)\n",
-           hif, address, buffer, length, request, context);
-
-       BUG_ON(!(request & (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS)));
-       BUG_ON(!(request & (HIF_BYTE_BASIS | HIF_BLOCK_BASIS)));
-       BUG_ON(!(request & (HIF_READ | HIF_WRITE)));
-       BUG_ON(!(request & HIF_EXTENDED_IO));
-
-       if (address >= HIF_MBOX_START_ADDR(0) &&
-           address < HIF_MBOX_START_ADDR(MBOXES+1)) {
-               BUG_ON(length > HIF_MBOX_WIDTH);
-               /* Adjust the address so that the last byte falls on the EOM
-                  address. */
-               address += HIF_MBOX_WIDTH-length;
-       }
-
-       req = kzalloc(sizeof(*req), GFP_ATOMIC);
-       if (!req) {
-               if (request & HIF_ASYNCHRONOUS)
-                       htcCallbacks.rwCompletionHandler(context, A_ERROR);
-               return A_ERROR;
-       }
-
-       req->func = hif->func;
-       req->addr = address;
-       req->buf = buffer;
-       req->len = length;
-
-       if (request & HIF_READ) {
-               if (request & HIF_FIXED_ADDRESS)
-                       req->read = sdio_readsb;
-               else
-                       req->read = sdio_memcpy_fromio;
-       } else {
-               if (request & HIF_FIXED_ADDRESS)
-                       req->write = sdio_writesb;
-               else
-                       req->write = sdio_memcpy_toio;
-       }
-
-       if (!(request & HIF_ASYNCHRONOUS))
-               return process_request(req);
-
-       req->completion = htcCallbacks.rwCompletionHandler;
-       req->context = context;
-       enqueue_request(hif, req);
-
-       return A_OK;
-}
-
-
-/* ----- Interrupt handling ------------------------------------------------ */
-
-/*
- * Volatile ought to be good enough to make gcc do the right thing on S3C24xx.
- * No need to use atomic or put barriers, keeping the code more readable.
- *
- * Warning: this story changes if going SMP/SMT.
- */
-
-static volatile int masked = 1;
-static volatile int pending;
-static volatile int in_interrupt;
-
-
-static void ar6000_do_irq(struct sdio_func *func)
-{
-       HIF_DEVICE *hif = sdio_get_drvdata(func);
-       struct device *dev = HIFGetOSDevice(hif);
-       A_STATUS status;
-
-       dev_dbg(dev, "ar6000_do_irq -> %p\n", htcCallbacks.dsrHandler);
-
-       status = htcCallbacks.dsrHandler(hif->htc_handle);
-       BUG_ON(status != A_OK);
-}
-
-
-static void sdio_ar6000_irq(struct sdio_func *func)
-{
-       HIF_DEVICE *hif = sdio_get_drvdata(func);
-       struct device *dev = HIFGetOSDevice(hif);
-
-       dev_dbg(dev, "sdio_ar6000_irq\n");
-
-       in_interrupt = 1;
-       if (masked) {
-               in_interrupt = 0;
-               pending++;
-               return;
-       }
-       /*
-        * @@@ This is ugly. If we don't drop the lock, we'll deadlock when
-        * the handler tries to do SDIO. So there are four choices:
-        *
-        * 1) Break the call chain by calling the callback from a workqueue.
-        *    Ugh.
-        * 2) Make process_request aware that we already have the lock.
-        * 3) Drop the lock. Which is ugly but should be safe as long as we're
-        *    making sure the device doesn't go away.
-        * 4) Change the AR6k driver such that it only issues asynchronous
-        *    quests when called from an interrupt.
-        *
-        * Solution 2) is probably the best for now. Will try it later.
-        */
-       sdio_release_host(func);
-       ar6000_do_irq(func);
-       sdio_claim_host(func);
-       in_interrupt = 0;
-}
-
-
-void HIFAckInterrupt(HIF_DEVICE *hif)
-{
-       struct device *dev = HIFGetOSDevice(hif);
-
-       dev_dbg(dev, "HIFAckInterrupt\n");
-       /* do nothing */
-}
-
-
-void HIFUnMaskInterrupt(HIF_DEVICE *hif)
-{
-       struct device *dev = HIFGetOSDevice(hif);
-
-       dev_dbg(dev, "HIFUnMaskInterrupt\n");
-       do {
-               masked = 1;
-               if (pending) {
-                       pending = 0;
-                       ar6000_do_irq(hif->func);
-                       /* We may take an interrupt before unmasking and thus
-                          get it pending. In this case, we just loop back. */
-               }
-               masked = 0;
-       }
-       while (pending);
-}
-
-
-void HIFMaskInterrupt(HIF_DEVICE *hif)
-{
-       struct device *dev = HIFGetOSDevice(hif);
-
-       dev_dbg(dev, "HIFMaskInterrupt\n");
-       /*
-        * Since sdio_ar6000_irq can also be called from a process context, we
-        * may conceivably end up racing with it. Thus, we need to wait until
-        * we can be sure that no concurrent interrupt processing is going on
-        * before we return.
-        *
-        * Note: this may be a bit on the paranoid side - the callers may
-        * actually be nice enough to disable scheduling. Check later.
-        */
-       masked = 1;
-       while (in_interrupt)
-               yield();
-}
-
-
-/* ----- HIF API glue functions -------------------------------------------- */
-
-
-struct device *HIFGetOSDevice(HIF_DEVICE *hif)
-{
-       return &hif->func->dev;
-}
-
-
-void HIFSetHandle(void *hif_handle, void *handle)
-{
-       HIF_DEVICE *hif = (HIF_DEVICE *) hif_handle;
-
-       hif->htc_handle = handle;
-}
-
-
-/* ----- Device configuration (HIF side) ----------------------------------- */
-
-
-A_STATUS HIFConfigureDevice(HIF_DEVICE *hif,
-    HIF_DEVICE_CONFIG_OPCODE opcode, void *config, A_UINT32 configLen)
-{
-       struct device *dev = HIFGetOSDevice(hif);
-       HIF_DEVICE_IRQ_PROCESSING_MODE *ipm_cfg = config;
-       A_UINT32 *mbs_cfg = config;
-       int i;
-
-       dev_dbg(dev, "HIFConfigureDevice\n");
-
-       switch (opcode) {
-       case HIF_DEVICE_GET_MBOX_BLOCK_SIZE:
-               for (i = 0; i != MBOXES; i++)
-                       mbs_cfg[i] = HIF_MBOX_BLOCK_SIZE;
-               break;
-       case HIF_DEVICE_GET_MBOX_ADDR:
-               for (i = 0; i != MBOXES; i++)
-                       mbs_cfg[i] = HIF_MBOX_START_ADDR(i);
-               break;
-       case HIF_DEVICE_GET_IRQ_PROC_MODE:
-               *ipm_cfg = HIF_DEVICE_IRQ_SYNC_ONLY;
-//             *ipm_cfg = HIF_DEVICE_IRQ_ASYNC_SYNC;
-               break;
-       default:
-               return A_ERROR;
-       }
-       return A_OK;
-}
-
-
-/* ----- Device probe and removal (Linux side) ----------------------------- */
-
-
-static int ar6000_do_activate(struct hif_device *hif)
-{
-       struct sdio_func *func = hif->func;
-       struct device *dev = &func->dev;
-       int ret;
-
-       dev_dbg(dev, "ar6000_do_activate\n");
-
-       sdio_claim_host(func);
-       sdio_enable_func(func);
-
-       INIT_LIST_HEAD(&hif->queue);
-       init_waitqueue_head(&hif->wait);
-       spin_lock_init(&hif->queue_lock);
-
-       ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE);
-       if (ret < 0) {
-               dev_err(dev, "sdio_set_block_size returns %d\n", ret);
-               goto out_enabled;
-       }
-       ret = sdio_claim_irq(func, sdio_ar6000_irq);
-       if (ret) {
-               dev_err(dev, "sdio_claim_irq returns %d\n", ret);
-               goto out_enabled;
-       }
-       /* Set SDIO_BUS_CD_DISABLE in SDIO_CCCR_IF ? */
-#if 0
-       sdio_f0_writeb(func, SDIO_CCCR_CAP_E4MI, SDIO_CCCR_CAPS, &ret);
-       if (ret) {
-               dev_err(dev, "sdio_f0_writeb(SDIO_CCCR_CAPS) returns %d\n",
-                   ret);
-               goto out_got_irq;
-       }
-#else
-       if (0) /* avoid warning */
-               goto out_got_irq;
-#endif
-
-       sdio_release_host(func);
-
-       hif->io_task = kthread_run(io, hif, "ar6000_io");
-       ret = IS_ERR(hif->io_task);
-       if (ret) {
-               dev_err(dev, "kthread_run(ar6000_io): %d\n", ret);
-               goto out_func_ready;
-       }
-
-       ret = htcCallbacks.deviceInsertedHandler(hif);
-       if (ret == A_OK)
-               return 0;
-
-       dev_err(dev, "deviceInsertedHandler: %d\n", ret);
-
-       ret = kthread_stop(hif->io_task);
-       if (ret)
-               dev_err(dev, "kthread_stop (ar6000_io): %d\n", ret);
-
-out_func_ready:
-       sdio_claim_host(func);
-
-out_got_irq:
-       sdio_release_irq(func);
-
-out_enabled:
-       sdio_disable_func(func);
-       sdio_release_host(func);
-
-       return ret;
-}
-
-
-static void ar6000_do_deactivate(struct hif_device *hif)
-{
-       struct sdio_func *func = hif->func;
-       struct device *dev = &func->dev;
-       int ret;
-
-       dev_dbg(dev, "ar6000_do_deactivate\n");
-       if (!hif->active)
-               return;
-
-       if (mutex_trylock(&shutdown_lock)) {
-               /*
-                * Funny, Atheros' HIF does this call, but this just puts us in
-                * a recursion through HTCShutDown/HIFShutDown if unloading the
-                * module.
-                *
-                * However, we need it for suspend/resume. See the comment at
-                * HIFShutDown, below.
-                */
-               ret = htcCallbacks.deviceRemovedHandler(hif->htc_handle, A_OK);
-               if (ret != A_OK)
-                       dev_err(dev, "deviceRemovedHandler: %d\n", ret);
-               mutex_unlock(&shutdown_lock);
-       }
-       wait_queue_empty(hif);
-       ret = kthread_stop(hif->io_task);
-       if (ret)
-               dev_err(dev, "kthread_stop (ar6000_io): %d\n", ret);
-       sdio_claim_host(func);
-       sdio_release_irq(func);
-       sdio_disable_func(func);
-       sdio_release_host(func);
-}
-
-
-static int ar6000_activate(struct hif_device *hif)
-{
-       int ret = 0;
-
-       dev_dbg(&hif->func->dev, "ar6000_activate\n");
-       mutex_lock(&hif->activate_lock);
-       if (!hif->active) {
-               ret = ar6000_do_activate(hif);
-               if (ret) {
-                       printk(KERN_ERR "%s: Failed to activate %d\n",
-                               __func__, ret);
-                       goto out;
-               }
-               hif->active = 1;
-       }
-out:
-       mutex_unlock(&hif->activate_lock);
-       return ret;
-}
-
-
-static void ar6000_deactivate(struct hif_device *hif)
-{
-       dev_dbg(&hif->func->dev, "ar6000_deactivate\n");
-       mutex_lock(&hif->activate_lock);
-       if (hif->active) {
-               ar6000_do_deactivate(hif);
-               hif->active = 0;
-       }
-       mutex_unlock(&hif->activate_lock);
-}
-
-
-static int ar6000_rfkill_cb(void *data, int on)
-{
-       struct hif_device *hif = data;
-       struct sdio_func *func = hif->func;
-       struct device *dev = &func->dev;
-
-       dev_dbg(dev, "ar6000_rfkill_cb: on %d\n", on);
-       if (on)
-               return ar6000_activate(hif);
-       ar6000_deactivate(hif);
-       return 0;
-}
-
-
-static int sdio_ar6000_probe(struct sdio_func *func,
-    const struct sdio_device_id *id)
-{
-       struct device *dev = &func->dev;
-       struct hif_device *hif;
-       int ret = 0;
-
-       dev_dbg(dev, "sdio_ar6000_probe\n");
-       BUG_ON(!htcCallbacks.deviceInsertedHandler);
-
-       hif = kzalloc(sizeof(*hif), GFP_KERNEL);
-       if (!hif)
-               return -ENOMEM;
-
-       sdio_set_drvdata(func, hif);
-       hif->func = func;
-       mutex_init(&hif->activate_lock);
-       hif->active = 0;
-
-       if (gta02_wlan_query_rfkill_lock())
-               ret = ar6000_activate(hif);
-       if (!ret) {
-               gta02_wlan_set_rfkill_cb(ar6000_rfkill_cb, hif);
-               return 0;
-       }
-       gta02_wlan_query_rfkill_unlock();
-       sdio_set_drvdata(func, NULL);
-       kfree(hif);
-       return ret;
-}
-
-
-static void sdio_ar6000_remove(struct sdio_func *func)
-{
-       struct device *dev = &func->dev;
-       HIF_DEVICE *hif = sdio_get_drvdata(func);
-
-       dev_dbg(dev, "sdio_ar6000_remove\n");
-       gta02_wlan_clear_rfkill_cb();
-       ar6000_deactivate(hif);
-       sdio_set_drvdata(func, NULL);
-       kfree(hif);
-}
-
-
-/* ----- Device registration/unregistration (called by HIF) ---------------- */
-
-
-#define ATHEROS_SDIO_DEVICE(id, offset) \
-    SDIO_DEVICE(SDIO_VENDOR_ID_ATHEROS, SDIO_DEVICE_ID_ATHEROS_##id | (offset))
-
-static const struct sdio_device_id sdio_ar6000_ids[] = {
-       { ATHEROS_SDIO_DEVICE(AR6002, 0)        },
-       { ATHEROS_SDIO_DEVICE(AR6002, 0x1)      },
-       { ATHEROS_SDIO_DEVICE(AR6001, 0x8)      },
-       { ATHEROS_SDIO_DEVICE(AR6001, 0x9)      },
-       { ATHEROS_SDIO_DEVICE(AR6001, 0xa)      },
-       { ATHEROS_SDIO_DEVICE(AR6001, 0xb)      },
-       { /* end: all zeroes */                 },
-};
-
-MODULE_DEVICE_TABLE(sdio, sdio_ar6000_ids);
-
-
-static struct sdio_driver sdio_ar6000_driver = {
-       .probe          = sdio_ar6000_probe,
-       .remove         = sdio_ar6000_remove,
-       .name           = "sdio_ar6000",
-       .id_table       = sdio_ar6000_ids,
-};
-
-
-int HIFInit(HTC_CALLBACKS *callbacks)
-{
-       int ret;
-
-       BUG_ON(!callbacks);
-
-       printk(KERN_DEBUG "HIFInit\n");
-       htcCallbacks = *callbacks;
-
-       ret = sdio_register_driver(&sdio_ar6000_driver);
-       if (ret) {
-               printk(KERN_ERR
-                   "sdio_register_driver(sdio_ar6000_driver): %d\n", ret);
-               return A_ERROR;
-       }
-
-       return 0;
-}
-
-
-/*
- * We have four possible call chains here:
- *
- * System shutdown/reboot:
- *
- *   kernel_restart_prepare ...> device_shutdown ... > s3cmci_shutdown ->
- *     mmc_remove_host ..> sdio_bus_remove -> sdio_ar6000_remove ->
- *     ar6000_deactivate -> ar6000_do_deactivate ->
- *     deviceRemovedHandler (HTCTargetRemovedHandler) -> HIFShutDownDevice
- *
- *   This is roughly the same sequence as suspend, described below.
- *
- * Module removal:
- *
- *   sys_delete_module -> ar6000_cleanup_module -> HTCShutDown ->
- *     HIFShutDownDevice -> sdio_unregister_driver ...> sdio_bus_remove ->
- *     sdio_ar6000_remove -> ar6000_deactivate -> ar6000_do_deactivate
- *
- *   In this case, HIFShutDownDevice must call sdio_unregister_driver to
- *   notify the driver about its removal. ar6000_do_deactivate must not call
- *   deviceRemovedHandler, because that would loop back into HIFShutDownDevice.
- *
- * Suspend:
- *
- *   device_suspend ...> s3cmci_suspend ...> sdio_bus_remove ->
- *     sdio_ar6000_remove -> ar6000_deactivate -> ar6000_do_deactivate ->
- *     deviceRemovedHandler (HTCTargetRemovedHandler) -> HIFShutDownDevice
- *
- *   We must call deviceRemovedHandler to inform the ar6k stack that the device
- *   has been removed. Since HTCTargetRemovedHandler calls back into
- *   HIFShutDownDevice, we must also prevent the call to
- *   sdio_unregister_driver, or we'd end up recursing into the SDIO stack,
- *   eventually deadlocking somewhere.
- *
- * rfkill:
- *
- *   rfkill_state_store -> rfkill_toggle_radio -> gta02_wlan_toggle_radio ->
- *   ar6000_rfkill_cb -> ar6000_deactivate -> ar6000_do_deactivate ->
- *     deviceRemovedHandler (HTCTargetRemovedHandler) -> HIFShutDownDevice
- *
- *   This is similar to suspend - only the entry point changes.
- */
-
-void HIFShutDownDevice(HIF_DEVICE *hif)
-{
-       /* Beware, HTCShutDown calls us with hif == NULL ! */
-       if (mutex_trylock(&shutdown_lock)) {
-               sdio_unregister_driver(&sdio_ar6000_driver);
-               mutex_unlock(&shutdown_lock);
-       }
-}