summaryrefslogtreecommitdiff
path: root/compat/compat/compat-2.6.27.c
diff options
context:
space:
mode:
Diffstat (limited to 'compat/compat/compat-2.6.27.c')
-rw-r--r--compat/compat/compat-2.6.27.c239
1 files changed, 239 insertions, 0 deletions
diff --git a/compat/compat/compat-2.6.27.c b/compat/compat/compat-2.6.27.c
new file mode 100644
index 00000000..084bdf6d
--- /dev/null
+++ b/compat/compat/compat-2.6.27.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
+ *
+ * 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.
+ *
+ * Compatibility file for Linux wireless for kernels 2.6.27
+ */
+
+#include <linux/compat.h>
+#include <linux/pci.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#endif
+
+/* rfkill notification chain */
+#define RFKILL_STATE_CHANGED 0x0001 /* state of a normal rfkill
+ switch has changed */
+
+/*
+ * e5899e1b7d73e67de758a32174a859cc2586c0b9 made pci_pme_capable() external,
+ * it was defined internally, some drivers want access to this information.
+ *
+ * Unfortunately the old kernels do not have ->pm_cap or ->pme_support so
+ * we have to call the PCI routines directly.
+ */
+
+/**
+ * pci_pme_capable - check the capability of PCI device to generate PME#
+ * @dev: PCI device to handle.
+ * @state: PCI state from which device will issue PME#.
+ *
+ * This is the backport code for older kernels for compat-drivers, we read stuff
+ * from the initialization stuff from pci_pm_init().
+ */
+bool pci_pme_capable(struct pci_dev *dev, pci_power_t state)
+{
+ int pm;
+ u16 pmc = 0;
+ u16 pme_support; /* as from the pci dev */
+ /* find PCI PM capability in list */
+ pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ if (!pm)
+ return false;
+
+ if ((pmc & PCI_PM_CAP_VER_MASK) > 3) {
+ dev_err(&dev->dev, "unsupported PM cap regs version (%u)\n",
+ pmc & PCI_PM_CAP_VER_MASK);
+ return false;
+ }
+
+ pmc &= PCI_PM_CAP_PME_MASK;
+
+ if (!pmc)
+ return false;
+
+ pme_support = pmc >> PCI_PM_CAP_PME_SHIFT;
+
+ /* Check device's ability to generate PME# */
+
+ return !!(pme_support & (1 << state));
+}
+EXPORT_SYMBOL_GPL(pci_pme_capable);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
+/**
+ * mmc_align_data_size - pads a transfer size to a more optimal value
+ * @card: the MMC card associated with the data transfer
+ * @sz: original transfer size
+ *
+ * Pads the original data size with a number of extra bytes in
+ * order to avoid controller bugs and/or performance hits
+ * (e.g. some controllers revert to PIO for certain sizes).
+ *
+ * Returns the improved size, which might be unmodified.
+ *
+ * Note that this function is only relevant when issuing a
+ * single scatter gather entry.
+ */
+unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz)
+{
+ /*
+ * FIXME: We don't have a system for the controller to tell
+ * the core about its problems yet, so for now we just 32-bit
+ * align the size.
+ */
+ sz = ((sz + 3) / 4) * 4;
+
+ return sz;
+}
+EXPORT_SYMBOL_GPL(mmc_align_data_size);
+
+/*
+ * Calculate the maximum byte mode transfer size
+ */
+static inline unsigned int sdio_max_byte_size(struct sdio_func *func)
+{
+ unsigned int mval = (unsigned int) min(func->card->host->max_seg_size,
+ func->card->host->max_blk_size);
+ mval = min(mval, func->max_blksize);
+ return min(mval, 512u); /* maximum size for byte mode */
+}
+
+/**
+ * sdio_align_size - pads a transfer size to a more optimal value
+ * @func: SDIO function
+ * @sz: original transfer size
+ *
+ * Pads the original data size with a number of extra bytes in
+ * order to avoid controller bugs and/or performance hits
+ * (e.g. some controllers revert to PIO for certain sizes).
+ *
+ * If possible, it will also adjust the size so that it can be
+ * handled in just a single request.
+ *
+ * Returns the improved size, which might be unmodified.
+ */
+unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz)
+{
+ unsigned int orig_sz;
+ unsigned int blk_sz, byte_sz;
+ unsigned chunk_sz;
+
+ orig_sz = sz;
+
+ /*
+ * Do a first check with the controller, in case it
+ * wants to increase the size up to a point where it
+ * might need more than one block.
+ */
+ sz = mmc_align_data_size(func->card, sz);
+
+ /*
+ * If we can still do this with just a byte transfer, then
+ * we're done.
+ */
+ if (sz <= sdio_max_byte_size(func))
+ return sz;
+
+ if (func->card->cccr.multi_block) {
+ /*
+ * Check if the transfer is already block aligned
+ */
+ if ((sz % func->cur_blksize) == 0)
+ return sz;
+
+ /*
+ * Realign it so that it can be done with one request,
+ * and recheck if the controller still likes it.
+ */
+ blk_sz = ((sz + func->cur_blksize - 1) /
+ func->cur_blksize) * func->cur_blksize;
+ blk_sz = mmc_align_data_size(func->card, blk_sz);
+
+ /*
+ * This value is only good if it is still just
+ * one request.
+ */
+ if ((blk_sz % func->cur_blksize) == 0)
+ return blk_sz;
+
+ /*
+ * We failed to do one request, but at least try to
+ * pad the remainder properly.
+ */
+ byte_sz = mmc_align_data_size(func->card,
+ sz % func->cur_blksize);
+ if (byte_sz <= sdio_max_byte_size(func)) {
+ blk_sz = sz / func->cur_blksize;
+ return blk_sz * func->cur_blksize + byte_sz;
+ }
+ } else {
+ /*
+ * We need multiple requests, so first check that the
+ * controller can handle the chunk size;
+ */
+ chunk_sz = mmc_align_data_size(func->card,
+ sdio_max_byte_size(func));
+ if (chunk_sz == sdio_max_byte_size(func)) {
+ /*
+ * Fix up the size of the remainder (if any)
+ */
+ byte_sz = orig_sz % chunk_sz;
+ if (byte_sz) {
+ byte_sz = mmc_align_data_size(func->card,
+ byte_sz);
+ }
+
+ return (orig_sz / chunk_sz) * chunk_sz + byte_sz;
+ }
+ }
+
+ /*
+ * The controller is simply incapable of transferring the size
+ * we want in decent manner, so just return the original size.
+ */
+ return orig_sz;
+}
+EXPORT_SYMBOL_GPL(sdio_align_size);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) */
+
+#ifdef CONFIG_DEBUG_FS
+/*
+ * Backport of debugfs_remove_recursive() without using the internals globals
+ * which are used by the kernel's version with:
+ * simple_release_fs(&debugfs_mount, &debugfs_mount_count);
+ */
+void debugfs_remove_recursive(struct dentry *dentry)
+{
+ struct dentry *last = NULL;
+
+ /* Sanity checks */
+ if (!dentry || !dentry->d_parent || !dentry->d_parent->d_inode)
+ return;
+
+ while (dentry != last) {
+ struct dentry *child = dentry;
+
+ /* Find a child without children */
+ while (!list_empty(&child->d_subdirs))
+ child = list_entry(child->d_subdirs.next,
+ struct dentry,
+ d_u.d_child);
+
+ /* Bail out if we already tried to remove that entry */
+ if (child == last)
+ return;
+
+ last = child;
+ debugfs_remove(child);
+ }
+}
+EXPORT_SYMBOL_GPL(debugfs_remove_recursive);
+#endif /* CONFIG_DEBUG_FS */
+