summaryrefslogtreecommitdiff
path: root/backport/compat
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2013-04-02 19:27:23 +0200
committerJohannes Berg <johannes@sipsolutions.net>2013-04-02 19:27:23 +0200
commit3ec07b8dc2ef11b1bfbdec3b6ed335b013be779b (patch)
tree42eaf82491e75302af703f7b8f5f048c76862da8 /backport/compat
parent3cefcdd73225e5404b077640ece987efff04216f (diff)
rename compat dir to backport
Then we can also move all the plumbing/ stuff into it. Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Diffstat (limited to 'backport/compat')
-rw-r--r--backport/compat/Kconfig98
-rw-r--r--backport/compat/Makefile51
-rw-r--r--backport/compat/average.c50
-rw-r--r--backport/compat/compat-2.6.14.c14
-rw-r--r--backport/compat/compat-2.6.18.c14
-rw-r--r--backport/compat/compat-2.6.19.c14
-rw-r--r--backport/compat/compat-2.6.21.c14
-rw-r--r--backport/compat/compat-2.6.22.c14
-rw-r--r--backport/compat/compat-2.6.23.c241
-rw-r--r--backport/compat/compat-2.6.24.c158
-rw-r--r--backport/compat/compat-2.6.25.c305
-rw-r--r--backport/compat/compat-2.6.26.c87
-rw-r--r--backport/compat/compat-2.6.27.c239
-rw-r--r--backport/compat/compat-2.6.28.c463
-rw-r--r--backport/compat/compat-2.6.29.c166
-rw-r--r--backport/compat/compat-2.6.32.c216
-rw-r--r--backport/compat/compat-2.6.33.c230
-rw-r--r--backport/compat/compat-2.6.34.c85
-rw-r--r--backport/compat/compat-2.6.34.h20
-rw-r--r--backport/compat/compat-2.6.35.c125
-rw-r--r--backport/compat/compat-2.6.36.c185
-rw-r--r--backport/compat/compat-2.6.37.c358
-rw-r--r--backport/compat/compat-2.6.39.c114
-rw-r--r--backport/compat/compat-3.0.c85
-rw-r--r--backport/compat/compat-3.1.c107
-rw-r--r--backport/compat/compat-3.2.c34
-rw-r--r--backport/compat/compat-3.3.c173
-rw-r--r--backport/compat/compat-3.4.c491
-rw-r--r--backport/compat/compat-3.5.c45
-rw-r--r--backport/compat/compat-3.6.c76
-rw-r--r--backport/compat/compat-3.7.c251
-rw-r--r--backport/compat/compat-3.8.c365
-rw-r--r--backport/compat/compat-3.9.c54
-rw-r--r--backport/compat/compat_atomic.c33
-rw-r--r--backport/compat/compat_firmware_class.c759
-rw-r--r--backport/compat/cordic.c101
-rw-r--r--backport/compat/crc8.c87
-rw-r--r--backport/compat/flow_dissector.c143
-rw-r--r--backport/compat/hid-ids.h866
-rw-r--r--backport/compat/kfifo.c608
-rw-r--r--backport/compat/kstrtox.c236
-rw-r--r--backport/compat/main.c63
-rw-r--r--backport/compat/pm_qos_params.c477
-rw-r--r--backport/compat/sch_codel.c306
-rw-r--r--backport/compat/sch_fq_codel_core.c659
-rw-r--r--backport/compat/user_namespace.c68
46 files changed, 9348 insertions, 0 deletions
diff --git a/backport/compat/Kconfig b/backport/compat/Kconfig
new file mode 100644
index 00000000..2bb11963
--- /dev/null
+++ b/backport/compat/Kconfig
@@ -0,0 +1,98 @@
+#
+# backport Kconfig
+#
+# Some options are user-selectable ("BACKPORT_USERSEL_*")
+#
+# Most options, however, follow a few different schemes:
+#
+# A) An option that is selected by drivers ("select FOO") will be
+# changed to "select BACKPORT_FOO" (if the option BACKPORT_FOO
+# exists). The option BACKPORT_FOO then controls setting of the
+# BACKPORT_BUILD_FOO option, which is a module, like this:
+#
+# config BACKPORT_BUILD_FOO
+# tristate
+# default m if BACKPORT_FOO && !FOO
+#
+# config BACKPORT_FOO
+# bool
+#
+# This only works as-is if the kernel code is usable on any version,
+# otherwise the "&& !FOO" part needs to be different.
+#
+#
+# B) An option for code always present on some kernels (e.g. KFIFO).
+# This simply depends on/sets the default based on the version:
+#
+# config BACKPORT_BUILD_KFIFO
+# def_bool y
+# depends on BACKPORT_KERNEL_2_6_36
+#
+#
+# C) similarly, a kconfig symbol for an option, e.g.
+# BACKPORT_OPTION_BT_SOCK_CREATE_NEEDS_KERN (see below)
+#
+#
+# Variations are obviously possible.
+#
+
+config BACKPORT_BUILD_FW_LOADER
+ tristate
+ # RHEL6, starting from 6.0, backports the FW loader already
+ depends on !BACKPORT_RHEL_KERNEL_6_0
+ default m if BACKPORT_FW_LOADER && (!FW_LOADER || BACKPORT_KERNEL_2_6_33)
+
+config BACKPORT_FW_LOADER
+ bool
+
+config BACKPORT_USERSEL_NET_SCH_CODEL
+ tristate "codel"
+ depends on m
+ depends on !BACKPORT_KERNEL_2_6_25
+ default m if NET_SCH_CODEL=n
+
+config BACKPORT_USERSEL_NET_SCH_FQ_CODEL
+ tristate "FQ codel"
+ depends on m
+ depends on !BACKPORT_KERNEL_2_6_25
+ default m if NET_SCH_FQ_CODEL=n
+
+config BACKPORT_BUILD_KFIFO
+ def_bool y
+ # RHEL6, starting from 6.1, backports kfifo already
+ depends on !BACKPORT_RHEL_KERNEL_6_1
+ depends on BACKPORT_KERNEL_2_6_36
+
+config BACKPORT_BUILD_CORDIC
+ tristate
+ default m if BACKPORT_CORDIC && !CORDIC
+
+config BACKPORT_CORDIC
+ bool
+
+config BACKPORT_BUILD_CRC8
+ tristate
+ default m if BACKPORT_CRC8 && !CRC8
+
+config BACKPORT_CRC8
+ bool
+
+config BACKPORT_BUILD_GENERIC_ATOMIC64
+ bool
+ default y if !64BIT && !GENERIC_ATOMIC64
+
+config BACKPORT_OPTION_BT_SOCK_CREATE_NEEDS_KERN
+ bool
+ # in RHEL6 (starting from 6.0), the function needs the argument
+ default y if !BACKPORT_KERNEL_2_6_33 || BACKPORT_RHEL_KERNEL_6_0
+
+config BACKPORT_BUILD_AVERAGE
+ bool
+ default y if !AVERAGE && BACKPORT_AVERAGE
+
+config BACKPORT_AVERAGE
+ bool
+
+config BACKPORT_OPTION_USB_URB_THREAD_FIX
+ bool
+ default y if BACKPORT_KERNEL_2_6_36
diff --git a/backport/compat/Makefile b/backport/compat/Makefile
new file mode 100644
index 00000000..62dd531c
--- /dev/null
+++ b/backport/compat/Makefile
@@ -0,0 +1,51 @@
+ccflags-y += -I$(src)
+ccflags-y += -DBACKPORTS_VERSION=\"$(BACKPORTS_VERSION)\"
+ccflags-y += -DBACKPORTED_KERNEL_VERSION=\"$(BACKPORTED_KERNEL_VERSION)\"
+ccflags-y += -DBACKPORTED_KERNEL_NAME=\"$(BACKPORTED_KERNEL_NAME)\"
+obj-m += compat.o
+compat-y += main.o
+
+obj-$(CPTCFG_BACKPORT_BUILD_FW_LOADER) += compat_firmware_class.o
+
+obj-$(CPTCFG_BACKPORT_USERSEL_NET_SCH_CODEL) += sch_codel.o
+
+sch_fq_codel-y = sch_fq_codel_core.o flow_dissector.o
+obj-$(CPTCFG_BACKPORT_USERSEL_NET_SCH_FQ_CODEL) += sch_fq_codel.o
+
+obj-$(CPTCFG_BACKPORT_BUILD_CORDIC) += cordic.o
+obj-$(CPTCFG_BACKPORT_BUILD_CRC8) += crc8.o
+
+# Compat kernel compatibility code
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_14) += compat-2.6.14.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_18) += compat-2.6.18.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_19) += compat-2.6.19.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_21) += compat-2.6.21.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_22) += compat-2.6.22.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_23) += compat-2.6.23.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_24) += compat-2.6.24.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_25) += compat-2.6.25.o pm_qos_params.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_26) += compat-2.6.26.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_27) += compat-2.6.27.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_28) += compat-2.6.28.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_29) += compat-2.6.29.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_32) += compat-2.6.32.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_33) += compat-2.6.33.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_34) += compat-2.6.34.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_35) += compat-2.6.35.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_36) += compat-2.6.36.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_37) += compat-2.6.37.o
+compat-$(CPTCFG_BACKPORT_BUILD_AVERAGE) += average.o
+compat-$(CPTCFG_BACKPORT_KERNEL_2_6_39) += compat-2.6.39.o kstrtox.o
+compat-$(CPTCFG_BACKPORT_KERNEL_3_0) += compat-3.0.o
+compat-$(CPTCFG_BACKPORT_KERNEL_3_1) += compat-3.1.o
+compat-$(CPTCFG_BACKPORT_KERNEL_3_2) += compat-3.2.o
+compat-$(CPTCFG_BACKPORT_KERNEL_3_3) += compat-3.3.o
+compat-$(CPTCFG_BACKPORT_KERNEL_3_4) += compat-3.4.o
+compat-$(CPTCFG_BACKPORT_KERNEL_3_5) += compat-3.5.o user_namespace.o
+compat-$(CPTCFG_BACKPORT_KERNEL_3_6) += compat-3.6.o
+compat-$(CPTCFG_BACKPORT_KERNEL_3_7) += compat-3.7.o
+compat-$(CPTCFG_BACKPORT_KERNEL_3_8) += compat-3.8.o
+compat-$(CPTCFG_BACKPORT_KERNEL_3_9) += compat-3.9.o
+
+compat-$(CPTCFG_BACKPORT_BUILD_KFIFO) += kfifo.o
+compat-$(CPTCFG_BACKPORT_BUILD_GENERIC_ATOMIC64) += compat_atomic.o
diff --git a/backport/compat/average.c b/backport/compat/average.c
new file mode 100644
index 00000000..37cbfd6b
--- /dev/null
+++ b/backport/compat/average.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * 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.38.
+ */
+
+#include <linux/average.h>
+#include <linux/module.h>
+#include <linux/bug.h>
+
+/**
+ * ewma_init() - Initialize EWMA parameters
+ * @avg: Average structure
+ * @factor: Factor to use for the scaled up internal value. The maximum value
+ * of averages can be ULONG_MAX/(factor*weight).
+ * @weight: Exponential weight, or decay rate. This defines how fast the
+ * influence of older values decreases. Has to be bigger than 1.
+ *
+ * Initialize the EWMA parameters for a given struct ewma @avg.
+ */
+void ewma_init(struct ewma *avg, unsigned long factor, unsigned long weight)
+{
+ WARN_ON(weight <= 1 || factor == 0);
+ avg->internal = 0;
+ avg->weight = weight;
+ avg->factor = factor;
+}
+EXPORT_SYMBOL_GPL(ewma_init);
+
+/**
+ * ewma_add() - Exponentially weighted moving average (EWMA)
+ * @avg: Average structure
+ * @val: Current value
+ *
+ * Add a sample to the average.
+ */
+struct ewma *ewma_add(struct ewma *avg, unsigned long val)
+{
+ avg->internal = avg->internal ?
+ (((avg->internal * (avg->weight - 1)) +
+ (val * avg->factor)) / avg->weight) :
+ (val * avg->factor);
+ return avg;
+}
+EXPORT_SYMBOL_GPL(ewma_add);
+
diff --git a/backport/compat/compat-2.6.14.c b/backport/compat/compat-2.6.14.c
new file mode 100644
index 00000000..3de847d9
--- /dev/null
+++ b/backport/compat/compat-2.6.14.c
@@ -0,0 +1,14 @@
+/*
+ * 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.14.
+ */
+
+#include <net/compat.h>
+
+/* 2.6.14 compat code goes here */
+
diff --git a/backport/compat/compat-2.6.18.c b/backport/compat/compat-2.6.18.c
new file mode 100644
index 00000000..c7961eeb
--- /dev/null
+++ b/backport/compat/compat-2.6.18.c
@@ -0,0 +1,14 @@
+/*
+ * 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.18.
+ */
+
+#include <net/compat.h>
+
+/* 2.6.18 compat code goes here */
+
diff --git a/backport/compat/compat-2.6.19.c b/backport/compat/compat-2.6.19.c
new file mode 100644
index 00000000..60c34045
--- /dev/null
+++ b/backport/compat/compat-2.6.19.c
@@ -0,0 +1,14 @@
+/*
+ * 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.19.
+ */
+
+#include <net/compat.h>
+
+/* 2.6.19 compat code goes here */
+
diff --git a/backport/compat/compat-2.6.21.c b/backport/compat/compat-2.6.21.c
new file mode 100644
index 00000000..7cf88619
--- /dev/null
+++ b/backport/compat/compat-2.6.21.c
@@ -0,0 +1,14 @@
+/*
+ * 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.21.
+ */
+
+#include <net/compat.h>
+
+/* 2.6.21 compat code goes here */
+
diff --git a/backport/compat/compat-2.6.22.c b/backport/compat/compat-2.6.22.c
new file mode 100644
index 00000000..d4df7b7d
--- /dev/null
+++ b/backport/compat/compat-2.6.22.c
@@ -0,0 +1,14 @@
+/*
+ * 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.22.
+ */
+
+#include <net/compat.h>
+
+/* 2.6.22 compat code goes here */
+
diff --git a/backport/compat/compat-2.6.23.c b/backport/compat/compat-2.6.23.c
new file mode 100644
index 00000000..1a76957d
--- /dev/null
+++ b/backport/compat/compat-2.6.23.c
@@ -0,0 +1,241 @@
+/*
+ * 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.23.
+ */
+
+#include <net/compat.h>
+
+/* On net/core/dev.c as of 2.6.24 */
+#define __dev_addr_delete LINUX_BACKPORT(__dev_addr_delete)
+int __dev_addr_delete(struct dev_addr_list **list, int *count,
+ void *addr, int alen, int glbl)
+{
+ struct dev_addr_list *da;
+
+ for (; (da = *list) != NULL; list = &da->next) {
+ if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 &&
+ alen == da->da_addrlen) {
+ if (glbl) {
+ int old_glbl = da->da_gusers;
+ da->da_gusers = 0;
+ if (old_glbl == 0)
+ break;
+ }
+ if (--da->da_users)
+ return 0;
+
+ *list = da->next;
+ kfree(da);
+ (*count)--;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(__dev_addr_delete);
+
+/* On net/core/dev.c as of 2.6.24. This is not yet used by mac80211 but
+ * might as well add it */
+#define __dev_addr_add LINUX_BACKPORT(__dev_addr_add)
+int __dev_addr_add(struct dev_addr_list **list, int *count,
+ void *addr, int alen, int glbl)
+{
+ struct dev_addr_list *da;
+
+ for (da = *list; da != NULL; da = da->next) {
+ if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 &&
+ da->da_addrlen == alen) {
+ if (glbl) {
+ int old_glbl = da->da_gusers;
+ da->da_gusers = 1;
+ if (old_glbl)
+ return 0;
+ }
+ da->da_users++;
+ return 0;
+ }
+ }
+
+ da = kmalloc(sizeof(*da), GFP_ATOMIC);
+ if (da == NULL)
+ return -ENOMEM;
+ memcpy(da->da_addr, addr, alen);
+ da->da_addrlen = alen;
+ da->da_users = 1;
+ da->da_gusers = glbl ? 1 : 0;
+ da->next = *list;
+ *list = da;
+ (*count)++;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__dev_addr_add);
+
+
+/* Part of net/core/dev_mcast.c as of 2.6.23. This is a slightly different version.
+ * Since da->da_synced is not part of 2.6.22 we need to take longer route when
+ * syncing */
+
+/**
+ * dev_mc_sync - Synchronize device's multicast list to another device
+ * @to: destination device
+ * @from: source device
+ *
+ * Add newly added addresses to the destination device and release
+ * addresses that have no users left. The source device must be
+ * locked by netif_tx_lock_bh.
+ *
+ * This function is intended to be called from the dev->set_multicast_list
+ * function of layered software devices.
+ */
+int dev_mc_sync(struct net_device *to, struct net_device *from)
+{
+ struct dev_addr_list *da, *next, *da_to;
+ int err = 0;
+
+ netif_tx_lock_bh(to);
+ da = from->mc_list;
+ while (da != NULL) {
+ int synced = 0;
+ next = da->next;
+ da_to = to->mc_list;
+ /* 2.6.22 does not have da->da_synced so lets take the long route */
+ while (da_to != NULL) {
+ if (memcmp(da_to->da_addr, da->da_addr, da_to->da_addrlen) == 0 &&
+ da->da_addrlen == da_to->da_addrlen)
+ synced = 1;
+ break;
+ }
+ if (!synced) {
+ err = __dev_addr_add(&to->mc_list, &to->mc_count,
+ da->da_addr, da->da_addrlen, 0);
+ if (err < 0)
+ break;
+ da->da_users++;
+ } else if (da->da_users == 1) {
+ __dev_addr_delete(&to->mc_list, &to->mc_count,
+ da->da_addr, da->da_addrlen, 0);
+ __dev_addr_delete(&from->mc_list, &from->mc_count,
+ da->da_addr, da->da_addrlen, 0);
+ }
+ da = next;
+ }
+ if (!err)
+ __dev_set_rx_mode(to);
+ netif_tx_unlock_bh(to);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(dev_mc_sync);
+
+
+/* Part of net/core/dev_mcast.c as of 2.6.23. This is a slighty different version.
+ * Since da->da_synced is not part of 2.6.22 we need to take longer route when
+ * unsyncing */
+
+/**
+ * dev_mc_unsync - Remove synchronized addresses from the destination
+ * device
+ * @to: destination device
+ * @from: source device
+ *
+ * Remove all addresses that were added to the destination device by
+ * dev_mc_sync(). This function is intended to be called from the
+ * dev->stop function of layered software devices.
+ */
+void dev_mc_unsync(struct net_device *to, struct net_device *from)
+{
+ struct dev_addr_list *da, *next, *da_to;
+
+ netif_tx_lock_bh(from);
+ netif_tx_lock_bh(to);
+
+ da = from->mc_list;
+ while (da != NULL) {
+ bool synced = false;
+ next = da->next;
+ da_to = to->mc_list;
+ /* 2.6.22 does not have da->da_synced so lets take the long route */
+ while (da_to != NULL) {
+ if (memcmp(da_to->da_addr, da->da_addr, da_to->da_addrlen) == 0 &&
+ da->da_addrlen == da_to->da_addrlen)
+ synced = true;
+ break;
+ }
+ if (!synced) {
+ da = next;
+ continue;
+ }
+ __dev_addr_delete(&to->mc_list, &to->mc_count,
+ da->da_addr, da->da_addrlen, 0);
+ __dev_addr_delete(&from->mc_list, &from->mc_count,
+ da->da_addr, da->da_addrlen, 0);
+ da = next;
+ }
+ __dev_set_rx_mode(to);
+
+ netif_tx_unlock_bh(to);
+ netif_tx_unlock_bh(from);
+}
+EXPORT_SYMBOL_GPL(dev_mc_unsync);
+
+/* Added as of 2.6.23 on net/core/dev.c. Slightly modifed, no dev->set_rx_mode on
+ * 2.6.22 so ignore that. */
+
+/*
+ * Upload unicast and multicast address lists to device and
+ * configure RX filtering. When the device doesn't support unicast
+ * filtering it is put in promiscous mode while unicast addresses
+ * are present.
+ */
+void __dev_set_rx_mode(struct net_device *dev)
+{
+ /* dev_open will call this function so the list will stay sane. */
+ if (!(dev->flags&IFF_UP))
+ return;
+
+ if (!netif_device_present(dev))
+ return;
+
+/* This needs to be ported to 2.6.22 framework */
+#if 0
+ /* Unicast addresses changes may only happen under the rtnl,
+ * therefore calling __dev_set_promiscuity here is safe.
+ */
+ if (dev->uc_count > 0 && !dev->uc_promisc) {
+ __dev_set_promiscuity(dev, 1);
+ dev->uc_promisc = 1;
+ } else if (dev->uc_count == 0 && dev->uc_promisc) {
+ __dev_set_promiscuity(dev, -1);
+ dev->uc_promisc = 0;
+ }
+#endif
+
+ if (dev->set_multicast_list)
+ dev->set_multicast_list(dev);
+}
+
+/**
+ * pci_try_set_mwi - enables memory-write-invalidate PCI transaction
+ * @dev: the PCI device for which MWI is enabled
+ *
+ * Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND.
+ * Callers are not required to check the return value.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int pci_try_set_mwi(struct pci_dev *dev)
+{
+ int rc = 0;
+#ifdef HAVE_PCI_SET_MWI
+ rc = pci_set_mwi(dev);
+#endif
+ return rc;
+}
+EXPORT_SYMBOL_GPL(pci_try_set_mwi);
+#endif
+
diff --git a/backport/compat/compat-2.6.24.c b/backport/compat/compat-2.6.24.c
new file mode 100644
index 00000000..977db0ca
--- /dev/null
+++ b/backport/compat/compat-2.6.24.c
@@ -0,0 +1,158 @@
+/*
+ * 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.24.
+ */
+
+#include <net/compat.h>
+#include <net/arp.h>
+
+/*
+ * We simply won't use it though, just declare it for our wrappers and
+ * for usage with tons of code that makes mention to it.
+ */
+struct net init_net;
+EXPORT_SYMBOL_GPL(init_net);
+
+/* 2.6.22 and 2.6.23 have eth_header_cache_update defined as extern in include/linux/etherdevice.h
+ * and actually defined in net/ethernet/eth.c but 2.6.24 exports it. Lets export it here */
+
+/**
+ * eth_header_cache_update - update cache entry
+ * @hh: destination cache entry
+ * @dev: network device
+ * @haddr: new hardware address
+ *
+ * Called by Address Resolution module to notify changes in address.
+ */
+void eth_header_cache_update(struct hh_cache *hh,
+ struct net_device *dev,
+ unsigned char *haddr)
+{
+ memcpy(((u8 *) hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)),
+ haddr, ETH_ALEN);
+}
+EXPORT_SYMBOL_GPL(eth_header_cache_update);
+
+/* 2.6.22 and 2.6.23 have eth_header_cache defined as extern in include/linux/etherdevice.h
+ * and actually defined in net/ethernet/eth.c but 2.6.24 exports it. Lets export it here */
+
+/**
+ * eth_header_cache - fill cache entry from neighbour
+ * @neigh: source neighbour
+ * @hh: destination cache entry
+ * Create an Ethernet header template from the neighbour.
+ */
+int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+{
+ __be16 type = hh->hh_type;
+ struct ethhdr *eth;
+ const struct net_device *dev = neigh->dev;
+
+ eth = (struct ethhdr *)
+ (((u8 *) hh->hh_data) + (HH_DATA_OFF(sizeof(*eth))));
+
+ if (type == htons(ETH_P_802_3))
+ return -1;
+
+ eth->h_proto = type;
+ memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
+ memcpy(eth->h_dest, neigh->ha, ETH_ALEN);
+ hh->hh_len = ETH_HLEN;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(eth_header_cache);
+
+/* 2.6.22 and 2.6.23 have eth_header() defined as extern in include/linux/etherdevice.h
+ * and actually defined in net/ethernet/eth.c but 2.6.24 exports it. Lets export it here */
+
+/**
+ * eth_header - create the Ethernet header
+ * @skb: buffer to alter
+ * @dev: source device
+ * @type: Ethernet type field
+ * @daddr: destination address (NULL leave destination address)
+ * @saddr: source address (NULL use device source address)
+ * @len: packet length (<= skb->len)
+ *
+ *
+ * Set the protocol type. For a packet of type ETH_P_802_3 we put the length
+ * in here instead. It is up to the 802.2 layer to carry protocol information.
+ */
+int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
+ void *daddr, void *saddr, unsigned len)
+{
+ struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+
+ if (type != ETH_P_802_3)
+ eth->h_proto = htons(type);
+ else
+ eth->h_proto = htons(len);
+
+ /*
+ * Set the source hardware address.
+ */
+
+ if (!saddr)
+ saddr = dev->dev_addr;
+ memcpy(eth->h_source, saddr, dev->addr_len);
+
+ if (daddr) {
+ memcpy(eth->h_dest, daddr, dev->addr_len);
+ return ETH_HLEN;
+ }
+
+ /*
+ * Anyway, the loopback-device should never use this function...
+ */
+
+ if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
+ memset(eth->h_dest, 0, dev->addr_len);
+ return ETH_HLEN;
+ }
+
+ return -ETH_HLEN;
+}
+
+EXPORT_SYMBOL_GPL(eth_header);
+
+/* 2.6.22 and 2.6.23 have eth_rebuild_header defined as extern in include/linux/etherdevice.h
+ * and actually defined in net/ethernet/eth.c but 2.6.24 exports it. Lets export it here */
+
+/**
+ * eth_rebuild_header- rebuild the Ethernet MAC header.
+ * @skb: socket buffer to update
+ *
+ * This is called after an ARP or IPV6 ndisc it's resolution on this
+ * sk_buff. We now let protocol (ARP) fill in the other fields.
+ *
+ * This routine CANNOT use cached dst->neigh!
+ * Really, it is used only when dst->neigh is wrong.
+ */
+int eth_rebuild_header(struct sk_buff *skb)
+{
+ struct ethhdr *eth = (struct ethhdr *)skb->data;
+ struct net_device *dev = skb->dev;
+
+ switch (eth->h_proto) {
+#ifdef CONFIG_INET
+ case __constant_htons(ETH_P_IP):
+ return arp_find(eth->h_dest, skb);
+#endif
+ default:
+ printk(KERN_DEBUG
+ "%s: unable to resolve type %X addresses.\n",
+ dev->name, (int)eth->h_proto);
+
+ memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
+ break;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(eth_rebuild_header);
+
diff --git a/backport/compat/compat-2.6.25.c b/backport/compat/compat-2.6.25.c
new file mode 100644
index 00000000..20cc3dbd
--- /dev/null
+++ b/backport/compat/compat-2.6.25.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2007-2012 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.25.
+ */
+
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+
+/*
+ * The default behaviour of sg_alloc_table() is to use these kmalloc/kfree
+ * helpers.
+ */
+static struct scatterlist *sg_kmalloc(unsigned int nents, gfp_t gfp_mask)
+{
+ if (nents == SG_MAX_SINGLE_ALLOC) {
+ return (struct scatterlist *) __get_free_page(gfp_mask);
+ } else
+ return kmalloc(nents * sizeof(struct scatterlist), gfp_mask);
+}
+
+static void sg_kfree(struct scatterlist *sg, unsigned int nents)
+{
+ if (nents == SG_MAX_SINGLE_ALLOC)
+ free_page((unsigned long) sg);
+ else
+ kfree(sg);
+}
+
+
+/**
+ * __sg_free_table - Free a previously mapped sg table
+ * @table: The sg table header to use
+ * @max_ents: The maximum number of entries per single scatterlist
+ * @free_fn: Free function
+ *
+ * Description:
+ * Free an sg table previously allocated and setup with
+ * __sg_alloc_table(). The @max_ents value must be identical to
+ * that previously used with __sg_alloc_table().
+ *
+ **/
+void __sg_free_table(struct sg_table *table, unsigned int max_ents,
+ sg_free_fn *free_fn)
+{
+ struct scatterlist *sgl, *next;
+
+ if (unlikely(!table->sgl))
+ return;
+
+ sgl = table->sgl;
+ while (table->orig_nents) {
+ unsigned int alloc_size = table->orig_nents;
+ unsigned int sg_size;
+
+ /*
+ * If we have more than max_ents segments left,
+ * then assign 'next' to the sg table after the current one.
+ * sg_size is then one less than alloc size, since the last
+ * element is the chain pointer.
+ */
+ if (alloc_size > max_ents) {
+ next = sg_chain_ptr(&sgl[max_ents - 1]);
+ alloc_size = max_ents;
+ sg_size = alloc_size - 1;
+ } else {
+ sg_size = alloc_size;
+ next = NULL;
+ }
+
+ table->orig_nents -= sg_size;
+ free_fn(sgl, alloc_size);
+ sgl = next;
+ }
+
+ table->sgl = NULL;
+}
+EXPORT_SYMBOL(__sg_free_table);
+
+/**
+ * sg_free_table - Free a previously allocated sg table
+ * @table: The mapped sg table header
+ *
+ **/
+void sg_free_table(struct sg_table *table)
+{
+ __sg_free_table(table, SG_MAX_SINGLE_ALLOC, sg_kfree);
+}
+EXPORT_SYMBOL(sg_free_table);
+
+/**
+ * __sg_alloc_table - Allocate and initialize an sg table with given allocator
+ * @table: The sg table header to use
+ * @nents: Number of entries in sg list
+ * @max_ents: The maximum number of entries the allocator returns per call
+ * @gfp_mask: GFP allocation mask
+ * @alloc_fn: Allocator to use
+ *
+ * Description:
+ * This function returns a @table @nents long. The allocator is
+ * defined to return scatterlist chunks of maximum size @max_ents.
+ * Thus if @nents is bigger than @max_ents, the scatterlists will be
+ * chained in units of @max_ents.
+ *
+ * Notes:
+ * If this function returns non-0 (eg failure), the caller must call
+ * __sg_free_table() to cleanup any leftover allocations.
+ *
+ **/
+int __sg_alloc_table(struct sg_table *table, unsigned int nents,
+ unsigned int max_ents, gfp_t gfp_mask,
+ sg_alloc_fn *alloc_fn)
+{
+ struct scatterlist *sg, *prv;
+ unsigned int left;
+
+#ifndef ARCH_HAS_SG_CHAIN
+ if (WARN_ON_ONCE(nents > max_ents))
+ return -EINVAL;
+#endif
+
+ memset(table, 0, sizeof(*table));
+
+ left = nents;
+ prv = NULL;
+ do {
+ unsigned int sg_size, alloc_size = left;
+
+ if (alloc_size > max_ents) {
+ alloc_size = max_ents;
+ sg_size = alloc_size - 1;
+ } else
+ sg_size = alloc_size;
+
+ left -= sg_size;
+
+ sg = alloc_fn(alloc_size, gfp_mask);
+ if (unlikely(!sg)) {
+ /*
+ * Adjust entry count to reflect that the last
+ * entry of the previous table won't be used for
+ * linkage. Without this, sg_kfree() may get
+ * confused.
+ */
+ if (prv)
+ table->nents = ++table->orig_nents;
+
+ return -ENOMEM;
+ }
+
+ sg_init_table(sg, alloc_size);
+ table->nents = table->orig_nents += sg_size;
+
+ /*
+ * If this is the first mapping, assign the sg table header.
+ * If this is not the first mapping, chain previous part.
+ */
+ if (prv)
+ sg_chain(prv, max_ents, sg);
+ else
+ table->sgl = sg;
+
+ /*
+ * If no more entries after this one, mark the end
+ */
+ if (!left)
+ sg_mark_end(&sg[sg_size - 1]);
+
+ prv = sg;
+ } while (left);
+
+ return 0;
+}
+EXPORT_SYMBOL(__sg_alloc_table);
+
+/**
+ * sg_alloc_table - Allocate and initialize an sg table
+ * @table: The sg table header to use
+ * @nents: Number of entries in sg list
+ * @gfp_mask: GFP allocation mask
+ *
+ * Description:
+ * Allocate and initialize an sg table. If @nents@ is larger than
+ * SG_MAX_SINGLE_ALLOC a chained sg table will be setup.
+ *
+ **/
+int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
+{
+ int ret;
+
+ ret = __sg_alloc_table(table, nents, SG_MAX_SINGLE_ALLOC,
+ gfp_mask, sg_kmalloc);
+ if (unlikely(ret))
+ __sg_free_table(table, SG_MAX_SINGLE_ALLOC, sg_kfree);
+
+ return ret;
+}
+EXPORT_SYMBOL(sg_alloc_table);
+
+
+/*
+ * To backport b718989d correctly pcibios_enable_device()
+ * is required but we don't have access to it on modules
+ * as its an architecture specific routine that is not
+ * exported and as such only core kernel code has access
+ * to it. We implement a sloppy work around for backporting
+ * this.
+ */
+int pci_enable_device_mem(struct pci_dev *dev)
+{
+ int bars = pci_select_bars(dev, IORESOURCE_MEM);
+
+ return pci_enable_device_bars(dev, bars);
+}
+EXPORT_SYMBOL_GPL(pci_enable_device_mem);
+
+/**
+ * The following things are out of ./lib/vsprintf.c
+ * The new iwlwifi driver is using them.
+ */
+
+/**
+ * strict_strtoul - convert a string to an unsigned long strictly
+ * @cp: The string to be converted
+ * @base: The number base to use
+ * @res: The converted result value
+ *
+ * strict_strtoul converts a string to an unsigned long only if the
+ * string is really an unsigned long string, any string containing
+ * any invalid char at the tail will be rejected and -EINVAL is returned,
+ * only a newline char at the tail is acceptible because people generally
+ * change a module parameter in the following way:
+ *
+ * echo 1024 > /sys/module/e1000/parameters/copybreak
+ *
+ * echo will append a newline to the tail.
+ *
+ * It returns 0 if conversion is successful and *res is set to the converted
+ * value, otherwise it returns -EINVAL and *res is set to 0.
+ *
+ * simple_strtoul just ignores the successive invalid characters and
+ * return the converted value of prefix part of the string.
+ */
+int strict_strtoul(const char *cp, unsigned int base, unsigned long *res);
+
+/**
+ * strict_strtol - convert a string to a long strictly
+ * @cp: The string to be converted
+ * @base: The number base to use
+ * @res: The converted result value
+ *
+ * strict_strtol is similiar to strict_strtoul, but it allows the first
+ * character of a string is '-'.
+ *
+ * It returns 0 if conversion is successful and *res is set to the converted
+ * value, otherwise it returns -EINVAL and *res is set to 0.
+ */
+int strict_strtol(const char *cp, unsigned int base, long *res);
+
+#define define_strict_strtoux(type, valtype) \
+int strict_strtou##type(const char *cp, unsigned int base, valtype *res)\
+{ \
+ char *tail; \
+ valtype val; \
+ size_t len; \
+ \
+ *res = 0; \
+ len = strlen(cp); \
+ if (len == 0) \
+ return -EINVAL; \
+ \
+ val = simple_strtou##type(cp, &tail, base); \
+ if ((*tail == '\0') || \
+ ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {\
+ *res = val; \
+ return 0; \
+ } \
+ \
+ return -EINVAL; \
+} \
+
+#define define_strict_strtox(type, valtype) \
+int strict_strto##type(const char *cp, unsigned int base, valtype *res) \
+{ \
+ int ret; \
+ if (*cp == '-') { \
+ ret = strict_strtou##type(cp+1, base, res); \
+ if (!ret) \
+ *res = -(*res); \
+ } else \
+ ret = strict_strtou##type(cp, base, res); \
+ \
+ return ret; \
+} \
+
+define_strict_strtoux(l, unsigned long)
+define_strict_strtox(l, long)
+
+EXPORT_SYMBOL_GPL(strict_strtoul);
+EXPORT_SYMBOL_GPL(strict_strtol);
+
diff --git a/backport/compat/compat-2.6.26.c b/backport/compat/compat-2.6.26.c
new file mode 100644
index 00000000..f4715067
--- /dev/null
+++ b/backport/compat/compat-2.6.26.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2007-2010 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.26.
+ *
+ * Copyright holders from ported work:
+ *
+ * Copyright (c) 2002-2003 Patrick Mochel <mochel@osdl.org>
+ * Copyright (c) 2006-2007 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (c) 2006-2007 Novell Inc.
+ */
+
+#include <net/compat.h>
+
+/* 2.6.24 does not have the struct kobject with a name */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25))
+
+/**
+ * kobject_set_name_vargs - Set the name of an kobject
+ * @kobj: struct kobject to set the name of
+ * @fmt: format string used to build the name
+ * @vargs: vargs to format the string.
+ */
+static
+int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
+ va_list vargs)
+{
+ const char *old_name = kobj->name;
+ char *s;
+
+ if (kobj->name && !fmt)
+ return 0;
+
+ kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
+ if (!kobj->name)
+ return -ENOMEM;
+
+ /* ewww... some of these buggers have '/' in the name ... */
+ while ((s = strchr(kobj->name, '/')))
+ s[0] = '!';
+
+ kfree(old_name);
+ return 0;
+}
+#else
+static
+int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
+ va_list vargs)
+{
+ struct device *dev;
+ unsigned int len;
+ va_list aq;
+
+ dev = container_of(kobj, struct device, kobj);
+
+ va_copy(aq, vargs);
+ len = vsnprintf(NULL, 0, fmt, aq);
+ va_end(aq);
+
+ len = len < BUS_ID_SIZE ? (len + 1) : BUS_ID_SIZE;
+
+ vsnprintf(dev->bus_id, len, fmt, vargs);
+ return 0;
+}
+#endif
+
+/**
+ * dev_set_name - set a device name
+ * @dev: device
+ * @fmt: format string for the device's name
+ */
+int dev_set_name(struct device *dev, const char *fmt, ...)
+{
+ va_list vargs;
+ int err;
+
+ va_start(vargs, fmt);
+ err = kobject_set_name_vargs(&dev->kobj, fmt, vargs);
+ va_end(vargs);
+ return err;
+}
+EXPORT_SYMBOL_GPL(dev_set_name);
+
diff --git a/backport/compat/compat-2.6.27.c b/backport/compat/compat-2.6.27.c
new file mode 100644
index 00000000..084bdf6d
--- /dev/null
+++ b/backport/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 */
+
diff --git a/backport/compat/compat-2.6.28.c b/backport/compat/compat-2.6.28.c
new file mode 100644
index 00000000..0ae8f465
--- /dev/null
+++ b/backport/compat/compat-2.6.28.c
@@ -0,0 +1,463 @@
+/*
+ * 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.28.
+ */
+
+#include <linux/compat.h>
+#include <linux/usb.h>
+#include <linux/tty.h>
+#include <asm/poll.h>
+
+/* 2.6.28 compat code goes here */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23))
+#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE)
+/*
+ * Compat-wireless notes for USB backport stuff:
+ *
+ * urb->reject exists on 2.6.27, the poison/unpoison helpers
+ * did not though. The anchor poison does not exist so we cannot use them.
+ *
+ * USB anchor poising seems to exist to prevent future driver sumbissions
+ * of usb_anchor_urb() to an anchor marked as poisoned. For older kernels
+ * we cannot use that, so new usb_anchor_urb()s will be anchored. The down
+ * side to this should be submission of URBs will continue being anchored
+ * on an anchor instead of having them being rejected immediately when the
+ * driver realized we needed to stop. For ar9170 we poison URBs upon the
+ * ar9170 mac80211 stop callback(), don't think this should be so bad.
+ * It mean there is period of time in older kernels for which we continue
+ * to anchor new URBs to a known stopped anchor. We have two anchors
+ * (TX, and RX)
+ */
+
+#if 0
+/**
+ * usb_poison_urb - reliably kill a transfer and prevent further use of an URB
+ * @urb: pointer to URB describing a previously submitted request,
+ * may be NULL
+ *
+ * This routine cancels an in-progress request. It is guaranteed that
+ * upon return all completion handlers will have finished and the URB
+ * will be totally idle and cannot be reused. These features make
+ * this an ideal way to stop I/O in a disconnect() callback.
+ * If the request has not already finished or been unlinked
+ * the completion handler will see urb->status == -ENOENT.
+ *
+ * After and while the routine runs, attempts to resubmit the URB will fail
+ * with error -EPERM. Thus even if the URB's completion handler always
+ * tries to resubmit, it will not succeed and the URB will become idle.
+ *
+ * This routine may not be used in an interrupt context (such as a bottom
+ * half or a completion handler), or when holding a spinlock, or in other
+ * situations where the caller can't schedule().
+ *
+ * This routine should not be called by a driver after its disconnect
+ * method has returned.
+ */
+void usb_poison_urb(struct urb *urb)
+{
+ might_sleep();
+ if (!(urb && urb->dev && urb->ep))
+ return;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
+ spin_lock_irq(&usb_reject_lock);
+#endif
+ ++urb->reject;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
+ spin_unlock_irq(&usb_reject_lock);
+#endif
+ /*
+ * XXX: usb_hcd_unlink_urb() needs backporting... this is defined
+ * on usb hcd.c but urb.c gets access to it. That is, older kernels
+ * have usb_hcd_unlink_urb() but its not exported, nor can we
+ * re-implement it exactly. This essentially dequeues the urb from
+ * hw, we need to figure out a way to backport this.
+ */
+ //usb_hcd_unlink_urb(urb, -ENOENT);
+
+ wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
+}
+EXPORT_SYMBOL_GPL(usb_poison_urb);
+#endif
+#endif /* CONFIG_USB */
+
+#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
+
+#include <pcmcia/ds.h>
+struct pcmcia_cfg_mem {
+ tuple_t tuple;
+ cisparse_t parse;
+ u8 buf[256];
+ cistpl_cftable_entry_t dflt;
+};
+/**
+ * pcmcia_loop_config() - loop over configuration options
+ * @p_dev: the struct pcmcia_device which we need to loop for.
+ * @conf_check: function to call for each configuration option.
+ * It gets passed the struct pcmcia_device, the CIS data
+ * describing the configuration option, and private data
+ * being passed to pcmcia_loop_config()
+ * @priv_data: private data to be passed to the conf_check function.
+ *
+ * pcmcia_loop_config() loops over all configuration options, and calls
+ * the driver-specific conf_check() for each one, checking whether
+ * it is a valid one. Returns 0 on success or errorcode otherwise.
+ */
+int pcmcia_loop_config(struct pcmcia_device *p_dev,
+ int (*conf_check) (struct pcmcia_device *p_dev,
+ cistpl_cftable_entry_t *cfg,
+ cistpl_cftable_entry_t *dflt,
+ unsigned int vcc,
+ void *priv_data),
+ void *priv_data)
+{
+ struct pcmcia_cfg_mem *cfg_mem;
+
+ tuple_t *tuple;
+ int ret;
+ unsigned int vcc;
+
+ cfg_mem = kzalloc(sizeof(struct pcmcia_cfg_mem), GFP_KERNEL);
+ if (cfg_mem == NULL)
+ return -ENOMEM;
+
+ /* get the current Vcc setting */
+ vcc = p_dev->socket->socket.Vcc;
+
+ tuple = &cfg_mem->tuple;
+ tuple->TupleData = cfg_mem->buf;
+ tuple->TupleDataMax = 255;
+ tuple->TupleOffset = 0;
+ tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ tuple->Attributes = 0;
+
+ ret = pcmcia_get_first_tuple(p_dev, tuple);
+ while (!ret) {
+ cistpl_cftable_entry_t *cfg = &cfg_mem->parse.cftable_entry;
+
+ if (pcmcia_get_tuple_data(p_dev, tuple))
+ goto next_entry;
+
+ if (pcmcia_parse_tuple(tuple, &cfg_mem->parse))
+ goto next_entry;
+
+ /* default values */
+ p_dev->conf.ConfigIndex = cfg->index;
+ if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
+ cfg_mem->dflt = *cfg;
+
+ ret = conf_check(p_dev, cfg, &cfg_mem->dflt, vcc, priv_data);
+ if (!ret)
+ break;
+
+next_entry:
+ ret = pcmcia_get_next_tuple(p_dev, tuple);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pcmcia_loop_config);
+
+#endif /* CONFIG_PCMCIA */
+
+#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE)
+
+void usb_unpoison_urb(struct urb *urb)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
+ unsigned long flags;
+#endif
+
+ if (!urb)
+ return;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
+ spin_lock_irqsave(&usb_reject_lock, flags);
+#endif
+ --urb->reject;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
+ spin_unlock_irqrestore(&usb_reject_lock, flags);
+#endif
+}
+EXPORT_SYMBOL_GPL(usb_unpoison_urb);
+
+
+#if 0
+/**
+ * usb_poison_anchored_urbs - cease all traffic from an anchor
+ * @anchor: anchor the requests are bound to
+ *
+ * this allows all outstanding URBs to be poisoned starting
+ * from the back of the queue. Newly added URBs will also be
+ * poisoned
+ *
+ * This routine should not be called by a driver after its disconnect
+ * method has returned.
+ */
+void usb_poison_anchored_urbs(struct usb_anchor *anchor)
+{
+ struct urb *victim;
+
+ spin_lock_irq(&anchor->lock);
+ // anchor->poisoned = 1; /* XXX: Cannot backport */
+ while (!list_empty(&anchor->urb_list)) {
+ victim = list_entry(anchor->urb_list.prev, struct urb,
+ anchor_list);
+ /* we must make sure the URB isn't freed before we kill it*/
+ usb_get_urb(victim);
+ spin_unlock_irq(&anchor->lock);
+ /* this will unanchor the URB */
+ usb_poison_urb(victim);
+ usb_put_urb(victim);
+ spin_lock_irq(&anchor->lock);
+ }
+ spin_unlock_irq(&anchor->lock);
+}
+EXPORT_SYMBOL_GPL(usb_poison_anchored_urbs);
+#endif
+
+/**
+ * usb_anchor_empty - is an anchor empty
+ * @anchor: the anchor you want to query
+ *
+ * returns 1 if the anchor has no urbs associated with it
+ */
+int usb_anchor_empty(struct usb_anchor *anchor)
+{
+ return list_empty(&anchor->urb_list);
+}
+
+EXPORT_SYMBOL_GPL(usb_anchor_empty);
+#endif /* CONFIG_USB */
+#endif
+
+void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar)
+{
+ /*
+ * Make sure the BAR is actually a memory resource, not an IO resource
+ */
+ if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
+ WARN_ON(1);
+ return NULL;
+ }
+ return ioremap_nocache(pci_resource_start(pdev, bar),
+ pci_resource_len(pdev, bar));
+}
+EXPORT_SYMBOL_GPL(pci_ioremap_bar);
+
+static unsigned long round_jiffies_common(unsigned long j, int cpu,
+ bool force_up)
+{
+ int rem;
+ unsigned long original = j;
+
+ /*
+ * We don't want all cpus firing their timers at once hitting the
+ * same lock or cachelines, so we skew each extra cpu with an extra
+ * 3 jiffies. This 3 jiffies came originally from the mm/ code which
+ * already did this.
+ * The skew is done by adding 3*cpunr, then round, then subtract this
+ * extra offset again.
+ */
+ j += cpu * 3;
+
+ rem = j % HZ;
+
+ /*
+ * If the target jiffie is just after a whole second (which can happen
+ * due to delays of the timer irq, long irq off times etc etc) then
+ * we should round down to the whole second, not up. Use 1/4th second
+ * as cutoff for this rounding as an extreme upper bound for this.
+ * But never round down if @force_up is set.
+ */
+ if (rem < HZ/4 && !force_up) /* round down */
+ j = j - rem;
+ else /* round up */
+ j = j - rem + HZ;
+
+ /* now that we have rounded, subtract the extra skew again */
+ j -= cpu * 3;
+
+ if (j <= jiffies) /* rounding ate our timeout entirely; */
+ return original;
+ return j;
+}
+
+/**
+ * round_jiffies_up - function to round jiffies up to a full second
+ * @j: the time in (absolute) jiffies that should be rounded
+ *
+ * This is the same as round_jiffies() except that it will never
+ * round down. This is useful for timeouts for which the exact time
+ * of firing does not matter too much, as long as they don't fire too
+ * early.
+ */
+unsigned long round_jiffies_up(unsigned long j)
+{
+ return round_jiffies_common(j, raw_smp_processor_id(), true);
+}
+EXPORT_SYMBOL_GPL(round_jiffies_up);
+
+void v2_6_28_skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
+ int size)
+{
+ skb_fill_page_desc(skb, i, page, off, size);
+ skb->len += size;
+ skb->data_len += size;
+ skb->truesize += size;
+}
+EXPORT_SYMBOL_GPL(v2_6_28_skb_add_rx_frag);
+
+void tty_write_unlock(struct tty_struct *tty)
+{
+ mutex_unlock(&tty->atomic_write_lock);
+ wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
+}
+
+int tty_write_lock(struct tty_struct *tty, int ndelay)
+{
+ if (!mutex_trylock(&tty->atomic_write_lock)) {
+ if (ndelay)
+ return -EAGAIN;
+ if (mutex_lock_interruptible(&tty->atomic_write_lock))
+ return -ERESTARTSYS;
+ }
+ return 0;
+}
+
+/**
+ * send_prio_char - send priority character
+ *
+ * Send a high priority character to the tty even if stopped
+ *
+ * Locking: none for xchar method, write ordering for write method.
+ */
+
+static int send_prio_char(struct tty_struct *tty, char ch)
+{
+ int was_stopped = tty->stopped;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
+ if (tty->ops->send_xchar) {
+ tty->ops->send_xchar(tty, ch);
+#else
+ if (tty->driver->send_xchar) {
+ tty->driver->send_xchar(tty, ch);
+#endif
+ return 0;
+ }
+
+ if (tty_write_lock(tty, 0) < 0)
+ return -ERESTARTSYS;
+
+ if (was_stopped)
+ start_tty(tty);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
+ tty->ops->write(tty, &ch, 1);
+#else
+ tty->driver->write(tty, &ch, 1);
+#endif
+ if (was_stopped)
+ stop_tty(tty);
+ tty_write_unlock(tty);
+ return 0;
+}
+
+int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
+ unsigned long flags;
+#endif
+ int retval;
+
+ switch (cmd) {
+ case TCXONC:
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ switch (arg) {
+ case TCOOFF:
+ if (!tty->flow_stopped) {
+ tty->flow_stopped = 1;
+ stop_tty(tty);
+ }
+ break;
+ case TCOON:
+ if (tty->flow_stopped) {
+ tty->flow_stopped = 0;
+ start_tty(tty);
+ }
+ break;
+ case TCIOFF:
+ if (STOP_CHAR(tty) != __DISABLED_CHAR)
+ return send_prio_char(tty, STOP_CHAR(tty));
+ break;
+ case TCION:
+ if (START_CHAR(tty) != __DISABLED_CHAR)
+ return send_prio_char(tty, START_CHAR(tty));
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ case TCFLSH:
+ return tty_perform_flush(tty, arg);
+ case TIOCPKT:
+ {
+ int pktmode;
+
+ if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
+ tty->driver->subtype != PTY_TYPE_MASTER)
+ return -ENOTTY;
+ if (get_user(pktmode, (int __user *) arg))
+ return -EFAULT;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+#endif
+ if (pktmode) {
+ if (!tty->packet) {
+ tty->packet = 1;
+ tty->link->ctrl_status = 0;
+ }
+ } else
+ tty->packet = 0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+#endif
+ return 0;
+ }
+ default:
+ /* Try the mode commands */
+ return tty_mode_ioctl(tty, file, cmd, arg);
+ }
+}
+EXPORT_SYMBOL_GPL(n_tty_ioctl_helper);
+
+/**
+ * pci_wake_from_d3 - enable/disable device to wake up from D3_hot or D3_cold
+ * @dev: PCI device to prepare
+ * @enable: True to enable wake-up event generation; false to disable
+ *
+ * Many drivers want the device to wake up the system from D3_hot or D3_cold
+ * and this function allows them to set that up cleanly - pci_enable_wake()
+ * should not be called twice in a row to enable wake-up due to PCI PM vs ACPI
+ * ordering constraints.
+ *
+ * This function only returns error code if the device is not capable of
+ * generating PME# from both D3_hot and D3_cold, and the platform is unable to
+ * enable wake-up power for it.
+ */
+int pci_wake_from_d3(struct pci_dev *dev, bool enable)
+{
+ return pci_pme_capable(dev, PCI_D3cold) ?
+ pci_enable_wake(dev, PCI_D3cold, enable) :
+ pci_enable_wake(dev, PCI_D3hot, enable);
+}
+EXPORT_SYMBOL_GPL(pci_wake_from_d3);
+
diff --git a/backport/compat/compat-2.6.29.c b/backport/compat/compat-2.6.29.c
new file mode 100644
index 00000000..1beb718d
--- /dev/null
+++ b/backport/compat/compat-2.6.29.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2007-2010 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.29.
+ */
+
+#include <linux/compat.h>
+#include <linux/usb.h>
+#include <linux/etherdevice.h>
+
+/*
+ * If you don't see your net_device_ops implemented on
+ * netdev_attach_ops() then you are shit out of luck and
+ * you must do the nasty ifdef magic, unless you figure
+ * out a way to squeze your hacks into this routine :)
+ */
+void netdev_attach_ops(struct net_device *dev,
+ const struct net_device_ops *ops)
+{
+ dev->open = ops->ndo_open;
+ dev->init = ops->ndo_init;
+ dev->stop = ops->ndo_stop;
+ dev->hard_start_xmit = ops->ndo_start_xmit;
+ dev->change_rx_flags = ops->ndo_change_rx_flags;
+ dev->set_multicast_list = ops->ndo_set_multicast_list;
+ dev->validate_addr = ops->ndo_validate_addr;
+ dev->do_ioctl = ops->ndo_do_ioctl;
+ dev->set_config = ops->ndo_set_config;
+ dev->change_mtu = ops->ndo_change_mtu;
+ dev->set_mac_address = ops->ndo_set_mac_address;
+ dev->tx_timeout = ops->ndo_tx_timeout;
+ if (ops->ndo_get_stats)
+ dev->get_stats = ops->ndo_get_stats;
+ dev->vlan_rx_register = ops->ndo_vlan_rx_register;
+ dev->vlan_rx_add_vid = ops->ndo_vlan_rx_add_vid;
+ dev->vlan_rx_kill_vid = ops->ndo_vlan_rx_kill_vid;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = ops->ndo_poll_controller;
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
+ dev->select_queue = ops->ndo_select_queue;
+#endif
+}
+EXPORT_SYMBOL_GPL(netdev_attach_ops);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23))
+#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE)
+/**
+ * usb_unpoison_anchored_urbs - let an anchor be used successfully again
+ * @anchor: anchor the requests are bound to
+ *
+ * Reverses the effect of usb_poison_anchored_urbs
+ * the anchor can be used normally after it returns
+ */
+void usb_unpoison_anchored_urbs(struct usb_anchor *anchor)
+{
+ unsigned long flags;
+ struct urb *lazarus;
+
+ spin_lock_irqsave(&anchor->lock, flags);
+ list_for_each_entry(lazarus, &anchor->urb_list, anchor_list) {
+ usb_unpoison_urb(lazarus);
+ }
+ //anchor->poisoned = 0; /* XXX: cannot backport */
+ spin_unlock_irqrestore(&anchor->lock, flags);
+}
+EXPORT_SYMBOL_GPL(usb_unpoison_anchored_urbs);
+#endif /* CONFIG_USB */
+#endif
+
+/**
+ * eth_mac_addr - set new Ethernet hardware address
+ * @dev: network device
+ * @p: socket address
+ * Change hardware address of device.
+ *
+ * This doesn't change hardware matching, so needs to be overridden
+ * for most real devices.
+ */
+int eth_mac_addr(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+
+ if (netif_running(dev))
+ return -EBUSY;
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+ memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(eth_mac_addr);
+
+/**
+ * eth_change_mtu - set new MTU size
+ * @dev: network device
+ * @new_mtu: new Maximum Transfer Unit
+ *
+ * Allow changing MTU size. Needs to be overridden for devices
+ * supporting jumbo frames.
+ */
+int eth_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if (new_mtu < 68 || new_mtu > ETH_DATA_LEN)
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(eth_change_mtu);
+
+int eth_validate_addr(struct net_device *dev)
+{
+ if (!is_valid_ether_addr(dev->dev_addr))
+ return -EADDRNOTAVAIL;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(eth_validate_addr);
+/* Source: net/ethernet/eth.c */
+
+#define NETREG_DUMMY 5
+/**
+ * init_dummy_netdev - init a dummy network device for NAPI
+ * @dev: device to init
+ *
+ * This takes a network device structure and initialize the minimum
+ * amount of fields so it can be used to schedule NAPI polls without
+ * registering a full blown interface. This is to be used by drivers
+ * that need to tie several hardware interfaces to a single NAPI
+ * poll scheduler due to HW limitations.
+ */
+int init_dummy_netdev(struct net_device *dev)
+{
+ /* Clear everything. Note we don't initialize spinlocks
+ * are they aren't supposed to be taken by any of the
+ * NAPI code and this dummy netdev is supposed to be
+ * only ever used for NAPI polls
+ */
+ memset(dev, 0, sizeof(struct net_device));
+
+ /* make sure we BUG if trying to hit standard
+ * register/unregister code path
+ */
+ dev->reg_state = NETREG_DUMMY;
+
+ /* initialize the ref count */
+ atomic_set(&dev->refcnt, 1);
+
+#ifdef CONFIG_NETPOLL
+ /* NAPI wants this */
+ INIT_LIST_HEAD(&dev->napi_list);
+#endif
+
+ /* a dummy interface is started by default */
+ set_bit(__LINK_STATE_PRESENT, &dev->state);
+ set_bit(__LINK_STATE_START, &dev->state);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(init_dummy_netdev);
+/* Source: net/core/dev.c */
+
diff --git a/backport/compat/compat-2.6.32.c b/backport/compat/compat-2.6.32.c
new file mode 100644
index 00000000..b5a66a86
--- /dev/null
+++ b/backport/compat/compat-2.6.32.c
@@ -0,0 +1,216 @@
+/*
+ * 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.32.
+ */
+
+#include <linux/compat.h>
+#include <linux/netdevice.h>
+
+int __dev_addr_add(struct dev_addr_list **list, int *count,
+ void *addr, int alen, int glbl)
+{
+ struct dev_addr_list *da;
+
+ for (da = *list; da != NULL; da = da->next) {
+ if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 &&
+ da->da_addrlen == alen) {
+ if (glbl) {
+ int old_glbl = da->da_gusers;
+ da->da_gusers = 1;
+ if (old_glbl)
+ return 0;
+ }
+ da->da_users++;
+ return 0;
+ }
+ }
+
+ da = kzalloc(sizeof(*da), GFP_ATOMIC);
+ if (da == NULL)
+ return -ENOMEM;
+ memcpy(da->da_addr, addr, alen);
+ da->da_addrlen = alen;
+ da->da_users = 1;
+ da->da_gusers = glbl ? 1 : 0;
+ da->next = *list;
+ *list = da;
+ (*count)++;
+ return 0;
+}
+
+int __dev_addr_delete(struct dev_addr_list **list, int *count,
+ void *addr, int alen, int glbl)
+{
+ struct dev_addr_list *da;
+
+ for (; (da = *list) != NULL; list = &da->next) {
+ if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 &&
+ alen == da->da_addrlen) {
+ if (glbl) {
+ int old_glbl = da->da_gusers;
+ da->da_gusers = 0;
+ if (old_glbl == 0)
+ break;
+ }
+ if (--da->da_users)
+ return 0;
+
+ *list = da->next;
+ kfree(da);
+ (*count)--;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+int __dev_addr_sync(struct dev_addr_list **to, int *to_count,
+ struct dev_addr_list **from, int *from_count)
+{
+ struct dev_addr_list *da, *next;
+ int err = 0;
+
+ da = *from;
+ while (da != NULL) {
+ next = da->next;
+ if (!da->da_synced) {
+ err = __dev_addr_add(to, to_count,
+ da->da_addr, da->da_addrlen, 0);
+ if (err < 0)
+ break;
+ da->da_synced = 1;
+ da->da_users++;
+ } else if (da->da_users == 1) {
+ __dev_addr_delete(to, to_count,
+ da->da_addr, da->da_addrlen, 0);
+ __dev_addr_delete(from, from_count,
+ da->da_addr, da->da_addrlen, 0);
+ }
+ da = next;
+ }
+ return err;
+}
+EXPORT_SYMBOL_GPL(__dev_addr_sync);
+
+void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
+ struct dev_addr_list **from, int *from_count)
+{
+ struct dev_addr_list *da, *next;
+
+ da = *from;
+ while (da != NULL) {
+ next = da->next;
+ if (da->da_synced) {
+ __dev_addr_delete(to, to_count,
+ da->da_addr, da->da_addrlen, 0);
+ da->da_synced = 0;
+ __dev_addr_delete(from, from_count,
+ da->da_addr, da->da_addrlen, 0);
+ }
+ da = next;
+ }
+}
+EXPORT_SYMBOL_GPL(__dev_addr_unsync);
+
+/*
+ * Nonzero if YEAR is a leap year (every 4 years,
+ * except every 100th isn't, and every 400th is).
+ */
+static int __isleap(long year)
+{
+ return (year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0);
+}
+
+/* do a mathdiv for long type */
+static long math_div(long a, long b)
+{
+ return a / b - (a % b < 0);
+}
+
+/* How many leap years between y1 and y2, y1 must less or equal to y2 */
+static long leaps_between(long y1, long y2)
+{
+ long leaps1 = math_div(y1 - 1, 4) - math_div(y1 - 1, 100)
+ + math_div(y1 - 1, 400);
+ long leaps2 = math_div(y2 - 1, 4) - math_div(y2 - 1, 100)
+ + math_div(y2 - 1, 400);
+ return leaps2 - leaps1;
+}
+
+/* How many days come before each month (0-12). */
+static const unsigned short __mon_yday[2][13] = {
+ /* Normal years. */
+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
+ /* Leap years. */
+ {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
+};
+
+#define SECS_PER_HOUR (60 * 60)
+#define SECS_PER_DAY (SECS_PER_HOUR * 24)
+
+/**
+ * time_to_tm - converts the calendar time to local broken-down time
+ *
+ * @totalsecs the number of seconds elapsed since 00:00:00 on January 1, 1970,
+ * Coordinated Universal Time (UTC).
+ * @offset offset seconds adding to totalsecs.
+ * @result pointer to struct tm variable to receive broken-down time
+ */
+void time_to_tm(time_t totalsecs, int offset, struct tm *result)
+{
+ long days, rem, y;
+ const unsigned short *ip;
+
+ days = totalsecs / SECS_PER_DAY;
+ rem = totalsecs % SECS_PER_DAY;
+ rem += offset;
+ while (rem < 0) {
+ rem += SECS_PER_DAY;
+ --days;
+ }
+ while (rem >= SECS_PER_DAY) {
+ rem -= SECS_PER_DAY;
+ ++days;
+ }
+
+ result->tm_hour = rem / SECS_PER_HOUR;
+ rem %= SECS_PER_HOUR;
+ result->tm_min = rem / 60;
+ result->tm_sec = rem % 60;
+
+ /* January 1, 1970 was a Thursday. */
+ result->tm_wday = (4 + days) % 7;
+ if (result->tm_wday < 0)
+ result->tm_wday += 7;
+
+ y = 1970;
+
+ while (days < 0 || days >= (__isleap(y) ? 366 : 365)) {
+ /* Guess a corrected year, assuming 365 days per year. */
+ long yg = y + math_div(days, 365);
+
+ /* Adjust DAYS and Y to match the guessed year. */
+ days -= (yg - y) * 365 + leaps_between(y, yg);
+ y = yg;
+ }
+
+ result->tm_year = y - 1900;
+
+ result->tm_yday = days;
+
+ ip = __mon_yday[__isleap(y)];
+ for (y = 11; days < ip[y]; y--)
+ continue;
+ days -= ip[y];
+
+ result->tm_mon = y;
+ result->tm_mday = days + 1;
+}
+EXPORT_SYMBOL_GPL(time_to_tm);
+/* source: kernel/time/timeconv.c*/
+
diff --git a/backport/compat/compat-2.6.33.c b/backport/compat/compat-2.6.33.c
new file mode 100644
index 00000000..f584b859
--- /dev/null
+++ b/backport/compat/compat-2.6.33.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2009 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * 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.33.
+ */
+
+#include <linux/compat.h>
+#include <linux/device.h>
+#include <linux/usb.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+
+#ifdef CONFIG_USB_SUSPEND
+/**
+ * usb_autopm_get_interface_no_resume - increment a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be incremented
+ *
+ * This routine increments @intf's usage counter but does not carry out an
+ * autoresume.
+ *
+ * This routine can run in atomic context.
+ */
+void usb_autopm_get_interface_no_resume(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+
+ usb_mark_last_busy(udev);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
+ atomic_inc(&intf->pm_usage_cnt);
+#else
+ intf->pm_usage_cnt++;
+#endif
+ pm_runtime_get_noresume(&intf->dev);
+}
+EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume);
+
+/**
+ * usb_autopm_put_interface_no_suspend - decrement a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be decremented
+ *
+ * This routine decrements @intf's usage counter but does not carry out an
+ * autosuspend.
+ *
+ * This routine can run in atomic context.
+ */
+void usb_autopm_put_interface_no_suspend(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+
+ usb_mark_last_busy(udev);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
+ atomic_dec(&intf->pm_usage_cnt);
+#else
+ intf->pm_usage_cnt--;
+#endif
+ pm_runtime_put_noidle(&intf->dev);
+}
+EXPORT_SYMBOL_GPL(usb_autopm_put_interface_no_suspend);
+#endif /* CONFIG_USB_SUSPEND */
+
+#if defined(CONFIG_PCCARD) || defined(CONFIG_PCCARD_MODULE)
+
+/**
+ * pccard_loop_tuple() - loop over tuples in the CIS
+ * @s: the struct pcmcia_socket where the card is inserted
+ * @function: the device function we loop for
+ * @code: which CIS code shall we look for?
+ * @parse: buffer where the tuple shall be parsed (or NULL, if no parse)
+ * @priv_data: private data to be passed to the loop_tuple function.
+ * @loop_tuple: function to call for each CIS entry of type @function. IT
+ * gets passed the raw tuple, the paresed tuple (if @parse is
+ * set) and @priv_data.
+ *
+ * pccard_loop_tuple() loops over all CIS entries of type @function, and
+ * calls the @loop_tuple function for each entry. If the call to @loop_tuple
+ * returns 0, the loop exits. Returns 0 on success or errorcode otherwise.
+ */
+int pccard_loop_tuple(struct pcmcia_socket *s, unsigned int function,
+ cisdata_t code, cisparse_t *parse, void *priv_data,
+ int (*loop_tuple) (tuple_t *tuple,
+ cisparse_t *parse,
+ void *priv_data))
+{
+ tuple_t tuple;
+ cisdata_t *buf;
+ int ret;
+
+ buf = kzalloc(256, GFP_KERNEL);
+ if (buf == NULL) {
+ dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n");
+ return -ENOMEM;
+ }
+
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = 255;
+ tuple.TupleOffset = 0;
+ tuple.DesiredTuple = code;
+ tuple.Attributes = 0;
+
+ ret = pccard_get_first_tuple(s, function, &tuple);
+ while (!ret) {
+ if (pccard_get_tuple_data(s, &tuple))
+ goto next_entry;
+
+ if (parse)
+ if (pcmcia_parse_tuple(&tuple, parse))
+ goto next_entry;
+
+ ret = loop_tuple(&tuple, parse, priv_data);
+ if (!ret)
+ break;
+
+next_entry:
+ ret = pccard_get_next_tuple(s, function, &tuple);
+ }
+
+ kfree(buf);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pccard_loop_tuple);
+/* Source: drivers/pcmcia/cistpl.c */
+
+#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
+
+struct pcmcia_loop_mem {
+ struct pcmcia_device *p_dev;
+ void *priv_data;
+ int (*loop_tuple) (struct pcmcia_device *p_dev,
+ tuple_t *tuple,
+ void *priv_data);
+};
+
+/**
+ * pcmcia_do_loop_tuple() - internal helper for pcmcia_loop_config()
+ *
+ * pcmcia_do_loop_tuple() is the internal callback for the call from
+ * pcmcia_loop_tuple() to pccard_loop_tuple(). Data is transferred
+ * by a struct pcmcia_cfg_mem.
+ */
+static int pcmcia_do_loop_tuple(tuple_t *tuple, cisparse_t *parse, void *priv)
+{
+ struct pcmcia_loop_mem *loop = priv;
+
+ return loop->loop_tuple(loop->p_dev, tuple, loop->priv_data);
+};
+
+/**
+ * pcmcia_loop_tuple() - loop over tuples in the CIS
+ * @p_dev: the struct pcmcia_device which we need to loop for.
+ * @code: which CIS code shall we look for?
+ * @priv_data: private data to be passed to the loop_tuple function.
+ * @loop_tuple: function to call for each CIS entry of type @function. IT
+ * gets passed the raw tuple and @priv_data.
+ *
+ * pcmcia_loop_tuple() loops over all CIS entries of type @function, and
+ * calls the @loop_tuple function for each entry. If the call to @loop_tuple
+ * returns 0, the loop exits. Returns 0 on success or errorcode otherwise.
+ */
+int pcmcia_loop_tuple(struct pcmcia_device *p_dev, cisdata_t code,
+ int (*loop_tuple) (struct pcmcia_device *p_dev,
+ tuple_t *tuple,
+ void *priv_data),
+ void *priv_data)
+{
+ struct pcmcia_loop_mem loop = {
+ .p_dev = p_dev,
+ .loop_tuple = loop_tuple,
+ .priv_data = priv_data};
+
+ return pccard_loop_tuple(p_dev->socket, p_dev->func, code, NULL,
+ &loop, pcmcia_do_loop_tuple);
+}
+EXPORT_SYMBOL_GPL(pcmcia_loop_tuple);
+/* Source: drivers/pcmcia/pcmcia_resource.c */
+
+#endif /* CONFIG_PCMCIA */
+
+#endif /* CONFIG_PCCARD */
+
+/**
+ * platform_device_register_data
+ * @parent: parent device for the device we're adding
+ * @name: base name of the device we're adding
+ * @id: instance id
+ * @data: platform specific data for this platform device
+ * @size: size of platform specific data
+ *
+ * This function creates a simple platform device that requires minimal
+ * resource and memory management. Canned release function freeing memory
+ * allocated for the device allows drivers using such devices to be
+ * unloaded without waiting for the last reference to the device to be
+ * dropped.
+ */
+struct platform_device *platform_device_register_data(
+ struct device *parent,
+ const char *name, int id,
+ const void *data, size_t size)
+{
+ struct platform_device *pdev;
+ int retval;
+
+ pdev = platform_device_alloc(name, id);
+ if (!pdev) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ pdev->dev.parent = parent;
+
+ if (size) {
+ retval = platform_device_add_data(pdev, data, size);
+ if (retval)
+ goto error;
+ }
+
+ retval = platform_device_add(pdev);
+ if (retval)
+ goto error;
+
+ return pdev;
+
+error:
+ platform_device_put(pdev);
+ return ERR_PTR(retval);
+}
+EXPORT_SYMBOL_GPL(platform_device_register_data);
diff --git a/backport/compat/compat-2.6.34.c b/backport/compat/compat-2.6.34.c
new file mode 100644
index 00000000..4b23c817
--- /dev/null
+++ b/backport/compat/compat-2.6.34.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012 Luis R. Rodriguez <mcgrof@do-not-panic.com>
+ *
+ * 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.34.
+ */
+
+#include <linux/mmc/sdio_func.h>
+
+#include "compat-2.6.34.h"
+
+static mmc_pm_flag_t backport_mmc_pm_flags;
+
+void backport_init_mmc_pm_flags(void)
+{
+ backport_mmc_pm_flags = 0;
+}
+
+mmc_pm_flag_t sdio_get_host_pm_caps(struct sdio_func *func)
+{
+ return backport_mmc_pm_flags;
+}
+
+int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags)
+{
+ return -EINVAL;
+}
+
+/**
+ * seq_hlist_start - start an iteration of a hlist
+ * @head: the head of the hlist
+ * @pos: the start position of the sequence
+ *
+ * Called at seq_file->op->start().
+ */
+struct hlist_node *seq_hlist_start(struct hlist_head *head, loff_t pos)
+{
+ struct hlist_node *node;
+
+ hlist_for_each(node, head)
+ if (pos-- == 0)
+ return node;
+ return NULL;
+}
+
+/**
+ * seq_hlist_start_head - start an iteration of a hlist
+ * @head: the head of the hlist
+ * @pos: the start position of the sequence
+ *
+ * Called at seq_file->op->start(). Call this function if you want to
+ * print a header at the top of the output.
+ */
+struct hlist_node *seq_hlist_start_head(struct hlist_head *head, loff_t pos)
+{
+ if (!pos)
+ return SEQ_START_TOKEN;
+
+ return seq_hlist_start(head, pos - 1);
+}
+EXPORT_SYMBOL_GPL(seq_hlist_start_head);
+
+/**
+ * seq_hlist_next - move to the next position of the hlist
+ * @v: the current iterator
+ * @head: the head of the hlist
+ * @ppos: the current position
+ *
+ * Called at seq_file->op->next().
+ */
+struct hlist_node *seq_hlist_next(void *v, struct hlist_head *head,
+ loff_t *ppos)
+{
+ struct hlist_node *node = v;
+
+ ++*ppos;
+ if (v == SEQ_START_TOKEN)
+ return head->first;
+ else
+ return node->next;
+}
+EXPORT_SYMBOL_GPL(seq_hlist_next);
diff --git a/backport/compat/compat-2.6.34.h b/backport/compat/compat-2.6.34.h
new file mode 100644
index 00000000..b36b441a
--- /dev/null
+++ b/backport/compat/compat-2.6.34.h
@@ -0,0 +1,20 @@
+#ifndef LINUX_26_34_COMPAT_PRIVATE_H
+#define LINUX_26_34_COMPAT_PRIVATE_H
+
+#include <linux/version.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34))
+
+#include <linux/mmc/sdio_func.h>
+
+void backport_init_mmc_pm_flags(void);
+
+#else /* Kernels >= 2.6.34 */
+
+static inline void backport_init_mmc_pm_flags(void)
+{
+}
+
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)) */
+
+#endif /* LINUX_26_34_COMPAT_PRIVATE_H */
diff --git a/backport/compat/compat-2.6.35.c b/backport/compat/compat-2.6.35.c
new file mode 100644
index 00000000..20fee853
--- /dev/null
+++ b/backport/compat/compat-2.6.35.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2010 Kshitij Kulshreshtha <kkhere.geo@gmail.com>
+ * Copyright 2012 Luis R. Rodriguez <mcgrof@do-not-panic.com>
+ *
+ * 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.35.
+ */
+
+#include <linux/compat.h>
+#include <linux/ctype.h>
+
+#ifdef CONFIG_RPS
+int netif_set_real_num_rx_queues(struct net_device *dev, unsigned int rxq)
+{
+ int rc;
+
+ /* we can't update the sysfs object for older kernels */
+ if (dev->reg_state == NETREG_REGISTERED)
+ return -EINVAL;
+ dev->num_rx_queues = rxq;
+ return 0;
+}
+#endif
+
+/*
+ * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues
+ * greater then real_num_tx_queues stale skbs on the qdisc must be flushed.
+ */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
+int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
+{
+ unsigned int real_num = dev->real_num_tx_queues;
+
+ if (unlikely(txq > dev->num_tx_queues))
+ return -EINVAL;
+ else if (txq > real_num)
+ dev->real_num_tx_queues = txq;
+ else if (txq < real_num) {
+ dev->real_num_tx_queues = txq;
+ qdisc_reset_all_tx_gt(dev, txq);
+ }
+ return 0;
+}
+#else
+int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
+{
+ dev->egress_subqueue_count = txq;
+ /* XXX: consider qdisc reset for older kernels */
+ return 0;
+}
+#endif
+EXPORT_SYMBOL_GPL(netif_set_real_num_tx_queues);
+
+/**
+ * hex_to_bin - convert a hex digit to its real value
+ * @ch: ascii character represents hex digit
+ *
+ * hex_to_bin() converts one hex digit to its actual value or -1 in case of bad
+ * input.
+ */
+int hex_to_bin(char ch)
+{
+ if ((ch >= '0') && (ch <= '9'))
+ return ch - '0';
+ ch = tolower(ch);
+ if ((ch >= 'a') && (ch <= 'f'))
+ return ch - 'a' + 10;
+ return -1;
+}
+EXPORT_SYMBOL_GPL(hex_to_bin);
+
+/**
+ * noop_llseek - No Operation Performed llseek implementation
+ * @file: file structure to seek on
+ * @offset: file offset to seek to
+ * @origin: type of seek
+ *
+ * This is an implementation of ->llseek useable for the rare special case when
+ * userspace expects the seek to succeed but the (device) file is actually not
+ * able to perform the seek. In this case you use noop_llseek() instead of
+ * falling back to the default implementation of ->llseek.
+ */
+loff_t noop_llseek(struct file *file, loff_t offset, int origin)
+{
+ return file->f_pos;
+}
+EXPORT_SYMBOL_GPL(noop_llseek);
+
+/**
+ * simple_write_to_buffer - copy data from user space to the buffer
+ * @to: the buffer to write to
+ * @available: the size of the buffer
+ * @ppos: the current position in the buffer
+ * @from: the user space buffer to read from
+ * @count: the maximum number of bytes to read
+ *
+ * The simple_write_to_buffer() function reads up to @count bytes from the user
+ * space address starting at @from into the buffer @to at offset @ppos.
+ *
+ * On success, the number of bytes written is returned and the offset @ppos is
+ * advanced by this number, or negative value is returned on error.
+ **/
+ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
+ const void __user *from, size_t count)
+{
+ loff_t pos = *ppos;
+ size_t res;
+
+ if (pos < 0)
+ return -EINVAL;
+ if (pos >= available || !count)
+ return 0;
+ if (count > available - pos)
+ count = available - pos;
+ res = copy_from_user(to + pos, from, count);
+ if (res == count)
+ return -EFAULT;
+ count -= res;
+ *ppos = pos + count;
+ return count;
+}
+EXPORT_SYMBOL_GPL(simple_write_to_buffer);
diff --git a/backport/compat/compat-2.6.36.c b/backport/compat/compat-2.6.36.c
new file mode 100644
index 00000000..92ef827a
--- /dev/null
+++ b/backport/compat/compat-2.6.36.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2010 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * 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.36.
+ */
+
+#include <linux/compat.h>
+#include <linux/usb.h>
+
+#ifdef CPTCFG_BACKPORT_OPTION_USB_URB_THREAD_FIX
+/* Callers must hold anchor->lock */
+static void __usb_unanchor_urb(struct urb *urb, struct usb_anchor *anchor)
+{
+ urb->anchor = NULL;
+ list_del(&urb->anchor_list);
+ usb_put_urb(urb);
+ if (list_empty(&anchor->urb_list))
+ wake_up(&anchor->wait);
+}
+
+/**
+ * usb_unlink_anchored_urbs - asynchronously cancel transfer requests en masse
+ * @anchor: anchor the requests are bound to
+ *
+ * this allows all outstanding URBs to be unlinked starting
+ * from the back of the queue. This function is asynchronous.
+ * The unlinking is just tiggered. It may happen after this
+ * function has returned.
+ *
+ * This routine should not be called by a driver after its disconnect
+ * method has returned.
+ */
+void usb_unlink_anchored_urbs(struct usb_anchor *anchor)
+{
+ struct urb *victim;
+
+ while ((victim = usb_get_from_anchor(anchor)) != NULL) {
+ usb_unlink_urb(victim);
+ usb_put_urb(victim);
+ }
+}
+EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs);
+
+/**
+ * usb_get_from_anchor - get an anchor's oldest urb
+ * @anchor: the anchor whose urb you want
+ *
+ * this will take the oldest urb from an anchor,
+ * unanchor and return it
+ */
+struct urb *usb_get_from_anchor(struct usb_anchor *anchor)
+{
+ struct urb *victim;
+ unsigned long flags;
+
+ spin_lock_irqsave(&anchor->lock, flags);
+ if (!list_empty(&anchor->urb_list)) {
+ victim = list_entry(anchor->urb_list.next, struct urb,
+ anchor_list);
+ usb_get_urb(victim);
+ __usb_unanchor_urb(victim, anchor);
+ } else {
+ victim = NULL;
+ }
+ spin_unlock_irqrestore(&anchor->lock, flags);
+
+ return victim;
+}
+EXPORT_SYMBOL_GPL(usb_get_from_anchor);
+
+/**
+ * usb_scuttle_anchored_urbs - unanchor all an anchor's urbs
+ * @anchor: the anchor whose urbs you want to unanchor
+ *
+ * use this to get rid of all an anchor's urbs
+ */
+void usb_scuttle_anchored_urbs(struct usb_anchor *anchor)
+{
+ struct urb *victim;
+ unsigned long flags;
+
+ spin_lock_irqsave(&anchor->lock, flags);
+ while (!list_empty(&anchor->urb_list)) {
+ victim = list_entry(anchor->urb_list.prev, struct urb,
+ anchor_list);
+ __usb_unanchor_urb(victim, anchor);
+ }
+ spin_unlock_irqrestore(&anchor->lock, flags);
+}
+EXPORT_SYMBOL_GPL(usb_scuttle_anchored_urbs);
+
+#endif /* CPTCFG_BACKPORT_OPTION_USB_URB_THREAD_FIX */
+
+struct workqueue_struct *system_wq __read_mostly;
+struct workqueue_struct *system_long_wq __read_mostly;
+struct workqueue_struct *system_nrt_wq __read_mostly;
+EXPORT_SYMBOL_GPL(system_wq);
+EXPORT_SYMBOL_GPL(system_long_wq);
+EXPORT_SYMBOL_GPL(system_nrt_wq);
+
+int schedule_work(struct work_struct *work)
+{
+ return queue_work(system_wq, work);
+}
+EXPORT_SYMBOL_GPL(schedule_work);
+
+int schedule_work_on(int cpu, struct work_struct *work)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
+ return queue_work_on(cpu, system_wq, work);
+#else
+ return queue_work(system_wq, work);
+#endif
+}
+EXPORT_SYMBOL_GPL(schedule_work_on);
+
+int schedule_delayed_work(struct delayed_work *dwork,
+ unsigned long delay)
+{
+ return queue_delayed_work(system_wq, dwork, delay);
+}
+EXPORT_SYMBOL_GPL(schedule_delayed_work);
+
+int schedule_delayed_work_on(int cpu,
+ struct delayed_work *dwork,
+ unsigned long delay)
+{
+ return queue_delayed_work_on(cpu, system_wq, dwork, delay);
+}
+EXPORT_SYMBOL_GPL(schedule_delayed_work_on);
+
+void flush_scheduled_work(void)
+{
+ /*
+ * It is debatable which one we should prioritize first, lets
+ * go with the old kernel's one first for now (keventd_wq) and
+ * if think its reasonable later we can flip this around.
+ */
+ flush_workqueue(system_wq);
+ flush_scheduled_work();
+}
+EXPORT_SYMBOL_GPL(flush_scheduled_work);
+
+/**
+ * work_busy - test whether a work is currently pending or running
+ * @work: the work to be tested
+ *
+ * Test whether @work is currently pending or running. There is no
+ * synchronization around this function and the test result is
+ * unreliable and only useful as advisory hints or for debugging.
+ * Especially for reentrant wqs, the pending state might hide the
+ * running state.
+ *
+ * RETURNS:
+ * OR'd bitmask of WORK_BUSY_* bits.
+ */
+unsigned int work_busy(struct work_struct *work)
+{
+ unsigned int ret = 0;
+
+ if (work_pending(work))
+ ret |= WORK_BUSY_PENDING;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(work_busy);
+
+void backport_system_workqueue_create(void)
+{
+ system_wq = alloc_workqueue("events", 0, 0);
+ system_long_wq = alloc_workqueue("events_long", 0, 0);
+ system_nrt_wq = create_singlethread_workqueue("events_nrt");
+ BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq);
+}
+
+void backport_system_workqueue_destroy(void)
+{
+ destroy_workqueue(system_wq);
+ destroy_workqueue(system_long_wq);
+ destroy_workqueue(system_nrt_wq);
+}
diff --git a/backport/compat/compat-2.6.37.c b/backport/compat/compat-2.6.37.c
new file mode 100644
index 00000000..9f722a62
--- /dev/null
+++ b/backport/compat/compat-2.6.37.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright 2010 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * 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.37.
+ */
+
+#include <linux/compat.h>
+#include <linux/netdevice.h>
+#include <net/sock.h>
+#include <linux/nsproxy.h>
+#include <linux/vmalloc.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
+static const void *net_current_ns(void)
+{
+ return current->nsproxy->net_ns;
+}
+
+static const void *net_initial_ns(void)
+{
+ return &init_net;
+}
+
+static const void *net_netlink_ns(struct sock *sk)
+{
+ return sock_net(sk);
+}
+
+struct kobj_ns_type_operations net_ns_type_operations = {
+ .type = KOBJ_NS_TYPE_NET,
+ .current_ns = net_current_ns,
+ .netlink_ns = net_netlink_ns,
+ .initial_ns = net_initial_ns,
+};
+EXPORT_SYMBOL_GPL(net_ns_type_operations);
+
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)*/
+
+#undef genl_info
+#undef genl_unregister_family
+
+static LIST_HEAD(compat_nl_fam);
+
+static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family)
+{
+ struct genl_ops *ops;
+
+ list_for_each_entry(ops, &family->family.ops_list, ops.ops_list)
+ if (ops->cmd == cmd)
+ return ops;
+
+ return NULL;
+}
+
+
+static int nl_doit_wrapper(struct sk_buff *skb, struct genl_info *info)
+{
+ struct compat_genl_info compat_info;
+ struct genl_family *family;
+ struct genl_ops *ops;
+ int err;
+
+ list_for_each_entry(family, &compat_nl_fam, list) {
+ if (family->id == info->nlhdr->nlmsg_type)
+ goto found;
+ }
+ return -ENOENT;
+
+found:
+ ops = genl_get_cmd(info->genlhdr->cmd, family);
+ if (!ops)
+ return -ENOENT;
+
+ memset(&compat_info.user_ptr, 0, sizeof(compat_info.user_ptr));
+ compat_info.info = info;
+#define __copy(_field) compat_info._field = info->_field
+ __copy(snd_seq);
+ __copy(snd_pid);
+ __copy(genlhdr);
+ __copy(attrs);
+#undef __copy
+ if (family->pre_doit) {
+ err = family->pre_doit(ops, skb, &compat_info);
+ if (err)
+ return err;
+ }
+
+ err = ops->doit(skb, &compat_info);
+
+ if (family->post_doit)
+ family->post_doit(ops, skb, &compat_info);
+
+ return err;
+}
+
+int compat_genl_register_family_with_ops(struct genl_family *family,
+ struct genl_ops *ops, size_t n_ops)
+{
+ int i, ret;
+
+#define __copy(_field) family->family._field = family->_field
+ __copy(id);
+ __copy(hdrsize);
+ __copy(version);
+ __copy(maxattr);
+ strncpy(family->family.name, family->name, sizeof(family->family.name));
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
+ __copy(netnsok);
+#endif
+#undef __copy
+
+ ret = genl_register_family(&family->family);
+ if (ret < 0)
+ return ret;
+
+ family->attrbuf = family->family.attrbuf;
+ family->id = family->family.id;
+
+ for (i = 0; i < n_ops; i++) {
+#define __copy(_field) ops[i].ops._field = ops[i]._field
+ __copy(cmd);
+ __copy(flags);
+ __copy(policy);
+ __copy(dumpit);
+ __copy(done);
+#undef __copy
+ if (ops[i].doit)
+ ops[i].ops.doit = nl_doit_wrapper;
+ ret = genl_register_ops(&family->family, &ops[i].ops);
+ if (ret < 0)
+ goto error_ops;
+ }
+ list_add(&family->list, &compat_nl_fam);
+
+ return ret;
+
+error_ops:
+ compat_genl_unregister_family(family);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(compat_genl_register_family_with_ops);
+
+int compat_genl_unregister_family(struct genl_family *family)
+{
+ int err;
+ err = genl_unregister_family(&family->family);
+ list_del(&family->list);
+ return err;
+}
+EXPORT_SYMBOL_GPL(compat_genl_unregister_family);
+
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+
+#undef led_brightness_set
+#undef led_classdev_unregister
+
+static DEFINE_SPINLOCK(led_lock);
+static LIST_HEAD(led_timers);
+
+struct led_timer {
+ struct list_head list;
+ struct led_classdev *cdev;
+ struct timer_list blink_timer;
+ unsigned long blink_delay_on;
+ unsigned long blink_delay_off;
+ int blink_brightness;
+};
+
+static void led_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ led_cdev->brightness = brightness;
+ led_cdev->brightness_set(led_cdev, brightness);
+}
+
+static struct led_timer *led_get_timer(struct led_classdev *led_cdev)
+{
+ struct led_timer *p;
+ unsigned long flags;
+
+ spin_lock_irqsave(&led_lock, flags);
+ list_for_each_entry(p, &led_timers, list) {
+ if (p->cdev == led_cdev)
+ goto found;
+ }
+ p = NULL;
+found:
+ spin_unlock_irqrestore(&led_lock, flags);
+ return p;
+}
+
+static void led_stop_software_blink(struct led_timer *led)
+{
+ del_timer_sync(&led->blink_timer);
+ led->blink_delay_on = 0;
+ led->blink_delay_off = 0;
+}
+
+static void led_timer_function(unsigned long data)
+{
+ struct led_timer *led = (struct led_timer *)data;
+ unsigned long brightness;
+ unsigned long delay;
+
+ if (!led->blink_delay_on || !led->blink_delay_off) {
+ led->cdev->brightness_set(led->cdev, LED_OFF);
+ return;
+ }
+
+ brightness = led->cdev->brightness;
+ if (!brightness) {
+ /* Time to switch the LED on. */
+ brightness = led->blink_brightness;
+ delay = led->blink_delay_on;
+ } else {
+ /* Store the current brightness value to be able
+ * to restore it when the delay_off period is over.
+ */
+ led->blink_brightness = brightness;
+ brightness = LED_OFF;
+ delay = led->blink_delay_off;
+ }
+
+ led_brightness_set(led->cdev, brightness);
+ mod_timer(&led->blink_timer, jiffies + msecs_to_jiffies(delay));
+}
+
+static struct led_timer *led_new_timer(struct led_classdev *led_cdev)
+{
+ struct led_timer *led;
+ unsigned long flags;
+
+ led = kzalloc(sizeof(struct led_timer), GFP_ATOMIC);
+ if (!led)
+ return NULL;
+
+ led->cdev = led_cdev;
+ init_timer(&led->blink_timer);
+ led->blink_timer.function = led_timer_function;
+ led->blink_timer.data = (unsigned long) led;
+
+ spin_lock_irqsave(&led_lock, flags);
+ list_add(&led->list, &led_timers);
+ spin_unlock_irqrestore(&led_lock, flags);
+
+ return led;
+}
+
+void led_blink_set(struct led_classdev *led_cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ struct led_timer *led;
+ int current_brightness;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25))
+ if (led_cdev->blink_set &&
+ !led_cdev->blink_set(led_cdev, delay_on, delay_off))
+ return;
+#endif
+
+ led = led_get_timer(led_cdev);
+ if (!led) {
+ led = led_new_timer(led_cdev);
+ if (!led)
+ return;
+ }
+
+ /* blink with 1 Hz as default if nothing specified */
+ if (!*delay_on && !*delay_off)
+ *delay_on = *delay_off = 500;
+
+ if (led->blink_delay_on == *delay_on &&
+ led->blink_delay_off == *delay_off)
+ return;
+
+ current_brightness = led_cdev->brightness;
+ if (current_brightness)
+ led->blink_brightness = current_brightness;
+ if (!led->blink_brightness)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
+ led->blink_brightness = led_cdev->max_brightness;
+#else
+ led->blink_brightness = LED_FULL;
+#endif
+
+ led_stop_software_blink(led);
+ led->blink_delay_on = *delay_on;
+ led->blink_delay_off = *delay_off;
+
+ /* never on - don't blink */
+ if (!*delay_on)
+ return;
+
+ /* never off - just set to brightness */
+ if (!*delay_off) {
+ led_brightness_set(led_cdev, led->blink_brightness);
+ return;
+ }
+
+ mod_timer(&led->blink_timer, jiffies + 1);
+}
+EXPORT_SYMBOL_GPL(led_blink_set);
+
+void compat_led_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct led_timer *led = led_get_timer(led_cdev);
+
+ if (led)
+ led_stop_software_blink(led);
+
+ return led_cdev->brightness_set(led_cdev, brightness);
+}
+EXPORT_SYMBOL_GPL(compat_led_brightness_set);
+
+void compat_led_classdev_unregister(struct led_classdev *led_cdev)
+{
+ struct led_timer *led = led_get_timer(led_cdev);
+ unsigned long flags;
+
+ if (led) {
+ del_timer_sync(&led->blink_timer);
+ spin_lock_irqsave(&led_lock, flags);
+ list_del(&led->list);
+ spin_unlock_irqrestore(&led_lock, flags);
+ kfree(led);
+ }
+
+ led_classdev_unregister(led_cdev);
+}
+EXPORT_SYMBOL_GPL(compat_led_classdev_unregister);
+
+/**
+ * vzalloc - allocate virtually contiguous memory with zero fill
+ * @size: allocation size
+ * Allocate enough pages to cover @size from the page level
+ * allocator and map them into contiguous kernel virtual space.
+ * The memory allocated is set to zero.
+ *
+ * For tight control over page level allocator and protection flags
+ * use __vmalloc() instead.
+ */
+void *vzalloc(unsigned long size)
+{
+ void *buf;
+ buf = vmalloc(size);
+ if (buf)
+ memset(buf, 0, size);
+ return buf;
+}
+EXPORT_SYMBOL_GPL(vzalloc);
+
+#endif
diff --git a/backport/compat/compat-2.6.39.c b/backport/compat/compat-2.6.39.c
new file mode 100644
index 00000000..5bb93221
--- /dev/null
+++ b/backport/compat/compat-2.6.39.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2011 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * 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.39.
+ */
+
+#include <linux/compat.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
+/*
+ * Termios Helper Methods
+ */
+static void unset_locked_termios(struct ktermios *termios,
+ struct ktermios *old,
+ struct ktermios *locked)
+{
+ int i;
+
+#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
+
+ if (!locked) {
+ printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
+ return;
+ }
+
+ NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
+ NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
+ NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
+ NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
+ termios->c_line = locked->c_line ? old->c_line : termios->c_line;
+ for (i = 0; i < NCCS; i++)
+ termios->c_cc[i] = locked->c_cc[i] ?
+ old->c_cc[i] : termios->c_cc[i];
+ /* FIXME: What should we do for i/ospeed */
+}
+
+/**
+ * tty_set_termios - update termios values
+ * @tty: tty to update
+ * @new_termios: desired new value
+ *
+ * Perform updates to the termios values set on this terminal. There
+ * is a bit of layering violation here with n_tty in terms of the
+ * internal knowledge of this function.
+ *
+ * Locking: termios_mutex
+ */
+int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
+{
+ struct ktermios old_termios;
+ struct tty_ldisc *ld;
+ unsigned long flags;
+
+ /*
+ * Perform the actual termios internal changes under lock.
+ */
+
+
+ /* FIXME: we need to decide on some locking/ordering semantics
+ for the set_termios notification eventually */
+ mutex_lock(&tty->termios_mutex);
+ old_termios = *tty->termios;
+ *tty->termios = *new_termios;
+ unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
+
+ /* See if packet mode change of state. */
+ if (tty->link && tty->link->packet) {
+ int extproc = (old_termios.c_lflag & EXTPROC) |
+ (tty->termios->c_lflag & EXTPROC);
+ int old_flow = ((old_termios.c_iflag & IXON) &&
+ (old_termios.c_cc[VSTOP] == '\023') &&
+ (old_termios.c_cc[VSTART] == '\021'));
+ int new_flow = (I_IXON(tty) &&
+ STOP_CHAR(tty) == '\023' &&
+ START_CHAR(tty) == '\021');
+ if ((old_flow != new_flow) || extproc) {
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ if (old_flow != new_flow) {
+ tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
+ if (new_flow)
+ tty->ctrl_status |= TIOCPKT_DOSTOP;
+ else
+ tty->ctrl_status |= TIOCPKT_NOSTOP;
+ }
+ if (extproc)
+ tty->ctrl_status |= TIOCPKT_IOCTL;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ wake_up_interruptible(&tty->link->read_wait);
+ }
+ }
+
+ if (tty->ops->set_termios)
+ (*tty->ops->set_termios)(tty, &old_termios);
+ else
+ tty_termios_copy_hw(tty->termios, &old_termios);
+
+ ld = tty_ldisc_ref(tty);
+ if (ld != NULL) {
+ if (ld->ops->set_termios)
+ (ld->ops->set_termios)(tty, &old_termios);
+ tty_ldisc_deref(ld);
+ }
+ mutex_unlock(&tty->termios_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tty_set_termios);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) */
+
diff --git a/backport/compat/compat-3.0.c b/backport/compat/compat-3.0.c
new file mode 100644
index 00000000..e8413730
--- /dev/null
+++ b/backport/compat/compat-3.0.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2011 Hauke Mehrtens <hauke@hauke-m.de>
+ * Copyright 2011 Alexey Dobriyan <adobriyan@gmail.com>
+ *
+ * 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 3.0.
+ */
+
+#include <linux/compat.h>
+#include <linux/if_ether.h>
+
+/* This pulls-in a lot of non-exported symbol backports
+ * on kernels older than 2.6.32. There's no harm for not
+ * making this available on kernels < 2.6.32. */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
+#include <linux/pagemap.h>
+
+/* This backports:
+ *
+ * commit d9d90e5eb70e09903dadff42099b6c948f814050
+ * Author: Hugh Dickins <hughd@google.com>
+ * Date: Mon Jun 27 16:18:04 2011 -0700
+ *
+ * tmpfs: add shmem_read_mapping_page_gfp
+ */
+
+struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
+ pgoff_t index, gfp_t gfp)
+{
+ return read_cache_page_gfp(mapping, index, gfp);
+}
+EXPORT_SYMBOL_GPL(shmem_read_mapping_page_gfp);
+#endif
+
+int mac_pton(const char *s, u8 *mac)
+{
+ int i;
+
+ /* XX:XX:XX:XX:XX:XX */
+ if (strlen(s) < 3 * ETH_ALEN - 1)
+ return 0;
+
+ /* Don't dirty result unless string is valid MAC. */
+ for (i = 0; i < ETH_ALEN; i++) {
+ if (!strchr("0123456789abcdefABCDEF", s[i * 3]))
+ return 0;
+ if (!strchr("0123456789abcdefABCDEF", s[i * 3 + 1]))
+ return 0;
+ if (i != ETH_ALEN - 1 && s[i * 3 + 2] != ':')
+ return 0;
+ }
+ for (i = 0; i < ETH_ALEN; i++) {
+ mac[i] = (hex_to_bin(s[i * 3]) << 4) | hex_to_bin(s[i * 3 + 1]);
+ }
+ return 1;
+}
+EXPORT_SYMBOL_GPL(mac_pton);
+
+#define kstrto_from_user(f, g, type) \
+int f(const char __user *s, size_t count, unsigned int base, type *res) \
+{ \
+ /* sign, base 2 representation, newline, terminator */ \
+ char buf[1 + sizeof(type) * 8 + 1 + 1]; \
+ \
+ count = min(count, sizeof(buf) - 1); \
+ if (copy_from_user(buf, s, count)) \
+ return -EFAULT; \
+ buf[count] = '\0'; \
+ return g(buf, base, res); \
+} \
+EXPORT_SYMBOL_GPL(f)
+
+kstrto_from_user(kstrtoull_from_user, kstrtoull, unsigned long long);
+kstrto_from_user(kstrtoll_from_user, kstrtoll, long long);
+kstrto_from_user(kstrtoul_from_user, kstrtoul, unsigned long);
+kstrto_from_user(kstrtol_from_user, kstrtol, long);
+kstrto_from_user(kstrtouint_from_user, kstrtouint, unsigned int);
+kstrto_from_user(kstrtoint_from_user, kstrtoint, int);
+kstrto_from_user(kstrtou16_from_user, kstrtou16, u16);
+kstrto_from_user(kstrtos16_from_user, kstrtos16, s16);
+kstrto_from_user(kstrtou8_from_user, kstrtou8, u8);
+kstrto_from_user(kstrtos8_from_user, kstrtos8, s8);
diff --git a/backport/compat/compat-3.1.c b/backport/compat/compat-3.1.c
new file mode 100644
index 00000000..cb5d596a
--- /dev/null
+++ b/backport/compat/compat-3.1.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * 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 3.1.
+ */
+
+#include <linux/idr.h>
+#include <linux/cpufreq.h>
+
+/* This backports:
+ * commit 3d73710880afa3d61cf57b5d4eb192e812eb7e4f
+ * Author: Jesse Barnes <jbarnes@virtuousgeek.org>
+ * Date: Tue Jun 28 10:59:12 2011 -0700
+ *
+ * cpufreq: expose a cpufreq_quick_get_max routine
+ */
+#ifdef CONFIG_CPU_FREQ
+unsigned int cpufreq_quick_get_max(unsigned int cpu)
+{
+ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+ unsigned int ret_freq = 0;
+
+ if (policy) {
+ ret_freq = policy->max;
+ cpufreq_cpu_put(policy);
+ }
+
+ return ret_freq;
+}
+EXPORT_SYMBOL_GPL(cpufreq_quick_get_max);
+#endif
+
+static DEFINE_SPINLOCK(compat_simple_ida_lock);
+
+/**
+ * ida_simple_get - get a new id.
+ * @ida: the (initialized) ida.
+ * @start: the minimum id (inclusive, < 0x8000000)
+ * @end: the maximum id (exclusive, < 0x8000000 or 0)
+ * @gfp_mask: memory allocation flags
+ *
+ * Allocates an id in the range start <= id < end, or returns -ENOSPC.
+ * On memory allocation failure, returns -ENOMEM.
+ *
+ * Use ida_simple_remove() to get rid of an id.
+ */
+int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
+ gfp_t gfp_mask)
+{
+ int ret, id;
+ unsigned int max;
+ unsigned long flags;
+
+ BUG_ON((int)start < 0);
+ BUG_ON((int)end < 0);
+
+ if (end == 0)
+ max = 0x80000000;
+ else {
+ BUG_ON(end < start);
+ max = end - 1;
+ }
+
+again:
+ if (!ida_pre_get(ida, gfp_mask))
+ return -ENOMEM;
+
+ spin_lock_irqsave(&compat_simple_ida_lock, flags);
+ ret = ida_get_new_above(ida, start, &id);
+ if (!ret) {
+ if (id > max) {
+ ida_remove(ida, id);
+ ret = -ENOSPC;
+ } else {
+ ret = id;
+ }
+ }
+ spin_unlock_irqrestore(&compat_simple_ida_lock, flags);
+
+ if (unlikely(ret == -EAGAIN))
+ goto again;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ida_simple_get);
+
+/**
+ * ida_simple_remove - remove an allocated id.
+ * @ida: the (initialized) ida.
+ * @id: the id returned by ida_simple_get.
+ */
+void ida_simple_remove(struct ida *ida, unsigned int id)
+{
+ unsigned long flags;
+
+ BUG_ON((int)id < 0);
+ spin_lock_irqsave(&compat_simple_ida_lock, flags);
+ ida_remove(ida, id);
+ spin_unlock_irqrestore(&compat_simple_ida_lock, flags);
+}
+EXPORT_SYMBOL_GPL(ida_simple_remove);
+/* source lib/idr.c */
+
diff --git a/backport/compat/compat-3.2.c b/backport/compat/compat-3.2.c
new file mode 100644
index 00000000..55ae6af0
--- /dev/null
+++ b/backport/compat/compat-3.2.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2012 Luis R. Rodriguez <mcgrof@frijolero.org>
+ *
+ * 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 3.2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+
+int __netdev_printk(const char *level, const struct net_device *dev,
+ struct va_format *vaf)
+{
+ int r;
+
+ if (dev && dev->dev.parent)
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
+ r = dev_printk(level, dev->dev.parent, "%s: %pV",
+ netdev_name(dev), vaf);
+#else
+ /* XXX: this could likely be done better but I'm lazy */
+ r = printk("%s%s: %pV", level, netdev_name(dev), vaf);
+#endif
+ else if (dev)
+ r = printk("%s%s: %pV", level, netdev_name(dev), vaf);
+ else
+ r = printk("%s(NULL net_device): %pV", level, vaf);
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(__netdev_printk);
diff --git a/backport/compat/compat-3.3.c b/backport/compat/compat-3.3.c
new file mode 100644
index 00000000..84893446
--- /dev/null
+++ b/backport/compat/compat-3.3.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2012 Luis R. Rodriguez <mcgrof@frijolero.org>
+ *
+ * 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 3.3.
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/skbuff.h>
+#include <linux/module.h>
+#include <net/dst.h>
+#include <net/xfrm.h>
+
+static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
+{
+ new->tstamp = old->tstamp;
+ new->dev = old->dev;
+ new->transport_header = old->transport_header;
+ new->network_header = old->network_header;
+ new->mac_header = old->mac_header;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
+ skb_dst_copy(new, old);
+ new->rxhash = old->rxhash;
+#else
+ skb_dst_set(new, dst_clone(skb_dst(old)));
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0))
+ new->ooo_okay = old->ooo_okay;
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0))
+ new->l4_rxhash = old->l4_rxhash;
+#endif
+#ifdef CONFIG_XFRM
+ new->sp = secpath_get(old->sp);
+#endif
+ memcpy(new->cb, old->cb, sizeof(old->cb));
+ new->csum = old->csum;
+ new->local_df = old->local_df;
+ new->pkt_type = old->pkt_type;
+ new->ip_summed = old->ip_summed;
+ skb_copy_queue_mapping(new, old);
+ new->priority = old->priority;
+#if IS_ENABLED(CONFIG_IP_VS)
+ new->ipvs_property = old->ipvs_property;
+#endif
+ new->protocol = old->protocol;
+ new->mark = old->mark;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33))
+ new->skb_iif = old->skb_iif;
+#endif
+ __nf_copy(new, old);
+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
+ new->nf_trace = old->nf_trace;
+#endif
+#ifdef CONFIG_NET_SCHED
+ new->tc_index = old->tc_index;
+#ifdef CONFIG_NET_CLS_ACT
+ new->tc_verd = old->tc_verd;
+#endif
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
+ new->vlan_tci = old->vlan_tci;
+#endif
+
+ skb_copy_secmark(new, old);
+}
+
+static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
+{
+#ifndef NET_SKBUFF_DATA_USES_OFFSET
+ /*
+ * Shift between the two data areas in bytes
+ */
+ unsigned long offset = new->data - old->data;
+#endif
+
+ __copy_skb_header(new, old);
+
+#ifndef NET_SKBUFF_DATA_USES_OFFSET
+ /* {transport,network,mac}_header are relative to skb->head */
+ new->transport_header += offset;
+ new->network_header += offset;
+ if (skb_mac_header_was_set(new))
+ new->mac_header += offset;
+#endif
+ skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;
+ skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
+ skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type;
+}
+
+static void skb_clone_fraglist(struct sk_buff *skb)
+{
+ struct sk_buff *list;
+
+ skb_walk_frags(skb, list)
+ skb_get(list);
+}
+
+
+/**
+ * __pskb_copy - create copy of an sk_buff with private head.
+ * @skb: buffer to copy
+ * @headroom: headroom of new skb
+ * @gfp_mask: allocation priority
+ *
+ * Make a copy of both an &sk_buff and part of its data, located
+ * in header. Fragmented data remain shared. This is used when
+ * the caller wishes to modify only header of &sk_buff and needs
+ * private copy of the header to alter. Returns %NULL on failure
+ * or the pointer to the buffer on success.
+ * The returned buffer has a reference count of 1.
+ */
+
+struct sk_buff *__pskb_copy(struct sk_buff *skb, int headroom, gfp_t gfp_mask)
+{
+ unsigned int size = skb_headlen(skb) + headroom;
+ struct sk_buff *n = alloc_skb(size, gfp_mask);
+
+ if (!n)
+ goto out;
+
+ /* Set the data pointer */
+ skb_reserve(n, headroom);
+ /* Set the tail pointer and length */
+ skb_put(n, skb_headlen(skb));
+ /* Copy the bytes */
+ skb_copy_from_linear_data(skb, n->data, n->len);
+
+ n->truesize += skb->data_len;
+ n->data_len = skb->data_len;
+ n->len = skb->len;
+
+ if (skb_shinfo(skb)->nr_frags) {
+ int i;
+
+/*
+ * SKBTX_DEV_ZEROCOPY was added on 3.1 as well but requires ubuf
+ * stuff added to the skb which we do not have
+ */
+#if 0
+ if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
+ if (skb_copy_ubufs(skb, gfp_mask)) {
+ kfree_skb(n);
+ n = NULL;
+ goto out;
+ }
+ }
+#endif
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0))
+ skb_frag_ref(skb, i);
+#else
+ get_page(skb_shinfo(skb)->frags[i].page);
+#endif
+ }
+ skb_shinfo(n)->nr_frags = i;
+ }
+
+ if (skb_has_frag_list(skb)) {
+ skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list;
+ skb_clone_fraglist(n);
+ }
+
+ copy_skb_header(n, skb);
+out:
+ return n;
+}
+EXPORT_SYMBOL_GPL(__pskb_copy);
diff --git a/backport/compat/compat-3.4.c b/backport/compat/compat-3.4.c
new file mode 100644
index 00000000..f8512e45
--- /dev/null
+++ b/backport/compat/compat-3.4.c
@@ -0,0 +1,491 @@
+/*
+ * Copyright 2012 Luis R. Rodriguez <mcgrof@frijolero.org>
+ *
+ * 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 3.4.
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/wait.h>
+
+/* __wake_up_common was declared as part of the wait.h until
+ * 2.6.31 in which they made it private to the scheduler. Prefix it with
+ * compat to avoid double declaration issues.
+ */
+static void compat_wake_up_common(wait_queue_head_t *q, unsigned int mode,
+ int nr_exclusive, int wake_flags, void *key)
+{
+ wait_queue_t *curr, *next;
+
+ list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
+ unsigned flags = curr->flags;
+
+ if (curr->func(curr, mode, wake_flags, key) &&
+ (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
+ break;
+ }
+}
+
+/* The last 'nr' parameter was added to the __wake_up_locked() function
+ * in 3.4 kernel. Define a new one prefixed with compat_ for the new API.
+ */
+void compat_wake_up_locked(wait_queue_head_t *q, unsigned int mode, int nr)
+{
+ compat_wake_up_common(q, mode, nr, 0, NULL);
+}
+EXPORT_SYMBOL_GPL(compat_wake_up_locked);
+
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/delay.h>
+
+#define setsda(adap, val) adap->setsda(adap->data, val)
+#define setscl(adap, val) adap->setscl(adap->data, val)
+#define getsda(adap) adap->getsda(adap->data)
+#define getscl(adap) adap->getscl(adap->data)
+
+#define bit_dbg(level, dev, format, args...) \
+ do {} while (0)
+
+static inline void sdalo(struct i2c_algo_bit_data *adap)
+{
+ setsda(adap, 0);
+ udelay((adap->udelay + 1) / 2);
+}
+
+static inline void sdahi(struct i2c_algo_bit_data *adap)
+{
+ setsda(adap, 1);
+ udelay((adap->udelay + 1) / 2);
+}
+
+static inline void scllo(struct i2c_algo_bit_data *adap)
+{
+ setscl(adap, 0);
+ udelay(adap->udelay / 2);
+}
+
+static int sclhi(struct i2c_algo_bit_data *adap)
+{
+ unsigned long start;
+
+ setscl(adap, 1);
+
+ /* Not all adapters have scl sense line... */
+ if (!adap->getscl)
+ goto done;
+
+ start = jiffies;
+ while (!getscl(adap)) {
+ /* This hw knows how to read the clock line, so we wait
+ * until it actually gets high. This is safer as some
+ * chips may hold it low ("clock stretching") while they
+ * are processing data internally.
+ */
+ if (time_after(jiffies, start + adap->timeout)) {
+ /* Test one last time, as we may have been preempted
+ * between last check and timeout test.
+ */
+ if (getscl(adap))
+ break;
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+#ifdef DEBUG
+ if (jiffies != start && i2c_debug >= 3)
+ pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go "
+ "high\n", jiffies - start);
+#endif
+
+done:
+ udelay(adap->udelay);
+ return 0;
+}
+
+static void i2c_start(struct i2c_algo_bit_data *adap)
+{
+ /* assert: scl, sda are high */
+ setsda(adap, 0);
+ udelay(adap->udelay);
+ scllo(adap);
+}
+
+static void i2c_repstart(struct i2c_algo_bit_data *adap)
+{
+ /* assert: scl is low */
+ sdahi(adap);
+ sclhi(adap);
+ setsda(adap, 0);
+ udelay(adap->udelay);
+ scllo(adap);
+}
+
+
+static void i2c_stop(struct i2c_algo_bit_data *adap)
+{
+ /* assert: scl is low */
+ sdalo(adap);
+ sclhi(adap);
+ setsda(adap, 1);
+ udelay(adap->udelay);
+}
+
+static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
+{
+ int i;
+ int sb;
+ int ack;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ /* assert: scl is low */
+ for (i = 7; i >= 0; i--) {
+ sb = (c >> i) & 1;
+ setsda(adap, sb);
+ udelay((adap->udelay + 1) / 2);
+ if (sclhi(adap) < 0) { /* timed out */
+ bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
+ "timeout at bit #%d\n", (int)c, i);
+ return -ETIMEDOUT;
+ }
+ /* FIXME do arbitration here:
+ * if (sb && !getsda(adap)) -> ouch! Get out of here.
+ *
+ * Report a unique code, so higher level code can retry
+ * the whole (combined) message and *NOT* issue STOP.
+ */
+ scllo(adap);
+ }
+ sdahi(adap);
+ if (sclhi(adap) < 0) { /* timeout */
+ bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
+ "timeout at ack\n", (int)c);
+ return -ETIMEDOUT;
+ }
+
+ /* read ack: SDA should be pulled down by slave, or it may
+ * NAK (usually to report problems with the data we wrote).
+ */
+ ack = !getsda(adap); /* ack: sda is pulled low -> success */
+ bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,
+ ack ? "A" : "NA");
+
+ scllo(adap);
+ return ack;
+ /* assert: scl is low (sda undef) */
+}
+
+static int i2c_inb(struct i2c_adapter *i2c_adap)
+{
+ /* read byte via i2c port, without start/stop sequence */
+ /* acknowledge is sent in i2c_read. */
+ int i;
+ unsigned char indata = 0;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ /* assert: scl is low */
+ sdahi(adap);
+ for (i = 0; i < 8; i++) {
+ if (sclhi(adap) < 0) { /* timeout */
+ bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit "
+ "#%d\n", 7 - i);
+ return -ETIMEDOUT;
+ }
+ indata *= 2;
+ if (getsda(adap))
+ indata |= 0x01;
+ setscl(adap, 0);
+ udelay(i == 7 ? adap->udelay / 2 : adap->udelay);
+ }
+ /* assert: scl is low */
+ return indata;
+}
+
+static int try_address(struct i2c_adapter *i2c_adap,
+ unsigned char addr, int retries)
+{
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+ int i, ret = 0;
+
+ for (i = 0; i <= retries; i++) {
+ ret = i2c_outb(i2c_adap, addr);
+ if (ret == 1 || i == retries)
+ break;
+ bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
+ i2c_stop(adap);
+ udelay(adap->udelay);
+ yield();
+ bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
+ i2c_start(adap);
+ }
+ if (i && ret)
+ bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at "
+ "0x%02x: %s\n", i + 1,
+ addr & 1 ? "read from" : "write to", addr >> 1,
+ ret == 1 ? "success" : "failed, timeout?");
+ return ret;
+}
+
+static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+ unsigned short flags = msg->flags;
+ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ unsigned char addr;
+ int ret, retries;
+
+ retries = nak_ok ? 0 : i2c_adap->retries;
+
+ if (flags & I2C_M_TEN) {
+ /* a ten bit address */
+ addr = 0xf0 | ((msg->addr >> 7) & 0x06);
+ bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr);
+ /* try extended address code...*/
+ ret = try_address(i2c_adap, addr, retries);
+ if ((ret != 1) && !nak_ok) {
+ dev_err(&i2c_adap->dev,
+ "died at extended address code\n");
+ return -ENXIO;
+ }
+ /* the remaining 8 bit address */
+ ret = i2c_outb(i2c_adap, msg->addr & 0xff);
+ if ((ret != 1) && !nak_ok) {
+ /* the chip did not ack / xmission error occurred */
+ dev_err(&i2c_adap->dev, "died at 2nd address code\n");
+ return -ENXIO;
+ }
+ if (flags & I2C_M_RD) {
+ bit_dbg(3, &i2c_adap->dev, "emitting repeated "
+ "start condition\n");
+ i2c_repstart(adap);
+ /* okay, now switch into reading mode */
+ addr |= 0x01;
+ ret = try_address(i2c_adap, addr, retries);
+ if ((ret != 1) && !nak_ok) {
+ dev_err(&i2c_adap->dev,
+ "died at repeated address code\n");
+ return -EIO;
+ }
+ }
+ } else { /* normal 7bit address */
+ addr = msg->addr << 1;
+ if (flags & I2C_M_RD)
+ addr |= 1;
+ if (flags & I2C_M_REV_DIR_ADDR)
+ addr ^= 1;
+ ret = try_address(i2c_adap, addr, retries);
+ if ((ret != 1) && !nak_ok)
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+ const unsigned char *temp = msg->buf;
+ int count = msg->len;
+ unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
+ int retval;
+ int wrcount = 0;
+
+ while (count > 0) {
+ retval = i2c_outb(i2c_adap, *temp);
+
+ /* OK/ACK; or ignored NAK */
+ if ((retval > 0) || (nak_ok && (retval == 0))) {
+ count--;
+ temp++;
+ wrcount++;
+
+ /* A slave NAKing the master means the slave didn't like
+ * something about the data it saw. For example, maybe
+ * the SMBus PEC was wrong.
+ */
+ } else if (retval == 0) {
+ dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n");
+ return -EIO;
+
+ /* Timeout; or (someday) lost arbitration
+ *
+ * FIXME Lost ARB implies retrying the transaction from
+ * the first message, after the "winning" master issues
+ * its STOP. As a rule, upper layer code has no reason
+ * to know or care about this ... it is *NOT* an error.
+ */
+ } else {
+ dev_err(&i2c_adap->dev, "sendbytes: error %d\n",
+ retval);
+ return retval;
+ }
+ }
+ return wrcount;
+}
+
+static int acknak(struct i2c_adapter *i2c_adap, int is_ack)
+{
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ /* assert: sda is high */
+ if (is_ack) /* send ack */
+ setsda(adap, 0);
+ udelay((adap->udelay + 1) / 2);
+ if (sclhi(adap) < 0) { /* timeout */
+ dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n");
+ return -ETIMEDOUT;
+ }
+ scllo(adap);
+ return 0;
+}
+
+static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+ int inval;
+ int rdcount = 0; /* counts bytes read */
+ unsigned char *temp = msg->buf;
+ int count = msg->len;
+ const unsigned flags = msg->flags;
+
+ while (count > 0) {
+ inval = i2c_inb(i2c_adap);
+ if (inval >= 0) {
+ *temp = inval;
+ rdcount++;
+ } else { /* read timed out */
+ break;
+ }
+
+ temp++;
+ count--;
+
+ /* Some SMBus transactions require that we receive the
+ transaction length as the first read byte. */
+ if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) {
+ if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {
+ if (!(flags & I2C_M_NO_RD_ACK))
+ acknak(i2c_adap, 0);
+ dev_err(&i2c_adap->dev, "readbytes: invalid "
+ "block length (%d)\n", inval);
+ return -EPROTO;
+ }
+ /* The original count value accounts for the extra
+ bytes, that is, either 1 for a regular transaction,
+ or 2 for a PEC transaction. */
+ count += inval;
+ msg->len += inval;
+ }
+
+ bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n",
+ inval,
+ (flags & I2C_M_NO_RD_ACK)
+ ? "(no ack/nak)"
+ : (count ? "A" : "NA"));
+
+ if (!(flags & I2C_M_NO_RD_ACK)) {
+ inval = acknak(i2c_adap, count);
+ if (inval < 0)
+ return inval;
+ }
+ }
+ return rdcount;
+}
+
+
+static u32 bit_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+ I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+static int bit_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[], int num)
+{
+ struct i2c_msg *pmsg;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+ int i, ret;
+ unsigned short nak_ok;
+
+ if (adap->pre_xfer) {
+ ret = adap->pre_xfer(i2c_adap);
+ if (ret < 0)
+ return ret;
+ }
+
+ bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
+ i2c_start(adap);
+ for (i = 0; i < num; i++) {
+ pmsg = &msgs[i];
+ nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
+ if (!(pmsg->flags & I2C_M_NOSTART)) {
+ if (i) {
+ bit_dbg(3, &i2c_adap->dev, "emitting "
+ "repeated start condition\n");
+ i2c_repstart(adap);
+ }
+ ret = bit_doAddress(i2c_adap, pmsg);
+ if ((ret != 0) && !nak_ok) {
+ bit_dbg(1, &i2c_adap->dev, "NAK from "
+ "device addr 0x%02x msg #%d\n",
+ msgs[i].addr, i);
+ goto bailout;
+ }
+ }
+ if (pmsg->flags & I2C_M_RD) {
+ /* read bytes into buffer*/
+ ret = readbytes(i2c_adap, pmsg);
+ if (ret >= 1)
+ bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n",
+ ret, ret == 1 ? "" : "s");
+ if (ret < pmsg->len) {
+ if (ret >= 0)
+ ret = -EIO;
+ goto bailout;
+ }
+ } else {
+ /* write bytes from buffer */
+ ret = sendbytes(i2c_adap, pmsg);
+ if (ret >= 1)
+ bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n",
+ ret, ret == 1 ? "" : "s");
+ if (ret < pmsg->len) {
+ if (ret >= 0)
+ ret = -EIO;
+ goto bailout;
+ }
+ }
+ }
+ ret = i;
+
+bailout:
+ bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
+ i2c_stop(adap);
+
+ if (adap->post_xfer)
+ adap->post_xfer(i2c_adap);
+ return ret;
+}
+
+
+const struct i2c_algorithm i2c_bit_algo = {
+ .master_xfer = bit_xfer,
+ .functionality = bit_func,
+};
+EXPORT_SYMBOL_GPL(i2c_bit_algo);
+#endif
+
+int simple_open(struct inode *inode, struct file *file)
+{
+ if (inode->i_private)
+ file->private_data = inode->i_private;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(simple_open);
diff --git a/backport/compat/compat-3.5.c b/backport/compat/compat-3.5.c
new file mode 100644
index 00000000..d7f1c275
--- /dev/null
+++ b/backport/compat/compat-3.5.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012-2013 Luis R. Rodriguez <mcgrof@do-not-panic.com>
+ *
+ * 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 3.5.
+ */
+
+#include <linux/module.h>
+#include <linux/highuid.h>
+#include <linux/ktime.h>
+
+/*
+ * Commit 7a4e7408c5cadb240e068a662251754a562355e3
+ * exported overflowuid and overflowgid for all
+ * kernel configurations, prior to that we only
+ * had it exported when CONFIG_UID16 was enabled.
+ * We are technically redefining it here but
+ * nothing seems to be changing it, except
+ * kernel/ code does epose it via sysctl and
+ * proc... if required later we can add that here.
+ */
+#ifndef CONFIG_UID16
+int overflowuid = DEFAULT_OVERFLOWUID;
+int overflowgid = DEFAULT_OVERFLOWGID;
+
+EXPORT_SYMBOL_GPL(overflowuid);
+EXPORT_SYMBOL_GPL(overflowgid);
+#endif
+
+/*
+ * We can't access the timekeeper static variable
+ * on older kernels so we're shit out of luck and
+ * have to rely on time that might jump. Upgrade
+ * if you want timestamps that don't jump, this
+ * important for DRM vblank and page flip event
+ * timestamps.
+ */
+ktime_t ktime_get_monotonic_offset(void)
+{
+ return ktime_get();
+}
+EXPORT_SYMBOL_GPL(ktime_get_monotonic_offset);
diff --git a/backport/compat/compat-3.6.c b/backport/compat/compat-3.6.c
new file mode 100644
index 00000000..113e3a86
--- /dev/null
+++ b/backport/compat/compat-3.6.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2013 Luis R. Rodriguez <mcgrof@do-not-panic.com>
+ *
+ * Backport compatibility file for Linux for kernels 3.6.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+
+/**
+ * sg_alloc_table_from_pages - Allocate and initialize an sg table from
+ * an array of pages
+ * @sgt: The sg table header to use
+ * @pages: Pointer to an array of page pointers
+ * @n_pages: Number of pages in the pages array
+ * @offset: Offset from start of the first page to the start of a buffer
+ * @size: Number of valid bytes in the buffer (after offset)
+ * @gfp_mask: GFP allocation mask
+ *
+ * Description:
+ * Allocate and initialize an sg table from a list of pages. Contiguous
+ * ranges of the pages are squashed into a single scatterlist node. A user
+ * may provide an offset at a start and a size of valid data in a buffer
+ * specified by the page array. The returned sg table is released by
+ * sg_free_table.
+ *
+ * Returns:
+ * 0 on success, negative error on failure
+ */
+int sg_alloc_table_from_pages(struct sg_table *sgt,
+ struct page **pages, unsigned int n_pages,
+ unsigned long offset, unsigned long size,
+ gfp_t gfp_mask)
+{
+ unsigned int chunks;
+ unsigned int i;
+ unsigned int cur_page;
+ int ret;
+ struct scatterlist *s;
+
+ /* compute number of contiguous chunks */
+ chunks = 1;
+ for (i = 1; i < n_pages; ++i)
+ if (page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1)
+ ++chunks;
+
+ ret = sg_alloc_table(sgt, chunks, gfp_mask);
+ if (unlikely(ret))
+ return ret;
+
+ /* merging chunks and putting them into the scatterlist */
+ cur_page = 0;
+ for_each_sg(sgt->sgl, s, sgt->orig_nents, i) {
+ unsigned long chunk_size;
+ unsigned int j;
+
+ /* look for the end of the current chunk */
+ for (j = cur_page + 1; j < n_pages; ++j)
+ if (page_to_pfn(pages[j]) !=
+ page_to_pfn(pages[j - 1]) + 1)
+ break;
+
+ chunk_size = ((j - cur_page) << PAGE_SHIFT) - offset;
+ sg_set_page(s, pages[cur_page], min(size, chunk_size), offset);
+ size -= chunk_size;
+ offset = 0;
+ cur_page = j;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sg_alloc_table_from_pages);
diff --git a/backport/compat/compat-3.7.c b/backport/compat/compat-3.7.c
new file mode 100644
index 00000000..226d136a
--- /dev/null
+++ b/backport/compat/compat-3.7.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2012 Luis R. Rodriguez <mcgrof@do-not-panic.com>
+ *
+ * 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 3.7.
+ */
+
+#include <linux/workqueue.h>
+#include <linux/export.h>
+
+bool mod_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork,
+ unsigned long delay)
+{
+ cancel_delayed_work(dwork);
+ queue_delayed_work(wq, dwork, delay);
+ return false;
+}
+EXPORT_SYMBOL_GPL(mod_delayed_work);
+
+/*
+ * Kernels >= 3.7 get their PCI-E Capabilities Register cached
+ * via the pci_dev->pcie_flags_reg so for older kernels we have
+ * no other option but to read this every single time we need
+ * it accessed. If we really cared to improve the efficiency
+ * of this we could try to find an unused u16 varible on the
+ * pci_dev but if we found it we likely would remove it from
+ * the kernel anyway right? Bite me.
+ */
+static inline u16 pcie_flags_reg(struct pci_dev *dev)
+{
+ int pos;
+ u16 reg16;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!pos)
+ return 0;
+
+ pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
+
+ return reg16;
+}
+
+static inline int pci_pcie_type(struct pci_dev *dev)
+{
+ return (pcie_flags_reg(dev) & PCI_EXP_FLAGS_TYPE) >> 4;
+}
+
+static inline int pcie_cap_version(struct pci_dev *dev)
+{
+ return pcie_flags_reg(dev) & PCI_EXP_FLAGS_VERS;
+}
+
+static inline bool pcie_cap_has_devctl(const struct pci_dev *dev)
+{
+ return true;
+}
+
+static inline bool pcie_cap_has_lnkctl(struct pci_dev *dev)
+{
+ int type = pci_pcie_type(dev);
+
+ return pcie_cap_version(dev) > 1 ||
+ type == PCI_EXP_TYPE_ROOT_PORT ||
+ type == PCI_EXP_TYPE_ENDPOINT ||
+ type == PCI_EXP_TYPE_LEG_END;
+}
+
+static inline bool pcie_cap_has_sltctl(struct pci_dev *dev)
+{
+ int type = pci_pcie_type(dev);
+
+ return pcie_cap_version(dev) > 1 ||
+ type == PCI_EXP_TYPE_ROOT_PORT ||
+ (type == PCI_EXP_TYPE_DOWNSTREAM &&
+ pcie_flags_reg(dev) & PCI_EXP_FLAGS_SLOT);
+}
+
+static inline bool pcie_cap_has_rtctl(struct pci_dev *dev)
+{
+ int type = pci_pcie_type(dev);
+
+ return pcie_cap_version(dev) > 1 ||
+ type == PCI_EXP_TYPE_ROOT_PORT ||
+ type == PCI_EXP_TYPE_RC_EC;
+}
+
+static bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
+{
+ if (!pci_is_pcie(dev))
+ return false;
+
+ switch (pos) {
+ case PCI_EXP_FLAGS_TYPE:
+ return true;
+ case PCI_EXP_DEVCAP:
+ case PCI_EXP_DEVCTL:
+ case PCI_EXP_DEVSTA:
+ return pcie_cap_has_devctl(dev);
+ case PCI_EXP_LNKCAP:
+ case PCI_EXP_LNKCTL:
+ case PCI_EXP_LNKSTA:
+ return pcie_cap_has_lnkctl(dev);
+ case PCI_EXP_SLTCAP:
+ case PCI_EXP_SLTCTL:
+ case PCI_EXP_SLTSTA:
+ return pcie_cap_has_sltctl(dev);
+ case PCI_EXP_RTCTL:
+ case PCI_EXP_RTCAP:
+ case PCI_EXP_RTSTA:
+ return pcie_cap_has_rtctl(dev);
+ case PCI_EXP_DEVCAP2:
+ case PCI_EXP_DEVCTL2:
+ case PCI_EXP_LNKCAP2:
+ case PCI_EXP_LNKCTL2:
+ case PCI_EXP_LNKSTA2:
+ return pcie_cap_version(dev) > 1;
+ default:
+ return false;
+ }
+}
+
+/*
+ * Note that these accessor functions are only for the "PCI Express
+ * Capability" (see PCIe spec r3.0, sec 7.8). They do not apply to the
+ * other "PCI Express Extended Capabilities" (AER, VC, ACS, MFVC, etc.)
+ */
+int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val)
+{
+ int ret;
+
+ *val = 0;
+ if (pos & 1)
+ return -EINVAL;
+
+ if (pcie_capability_reg_implemented(dev, pos)) {
+ ret = pci_read_config_word(dev, pci_pcie_cap(dev) + pos, val);
+ /*
+ * Reset *val to 0 if pci_read_config_word() fails, it may
+ * have been written as 0xFFFF if hardware error happens
+ * during pci_read_config_word().
+ */
+ if (ret)
+ *val = 0;
+ return ret;
+ }
+
+ /*
+ * For Functions that do not implement the Slot Capabilities,
+ * Slot Status, and Slot Control registers, these spaces must
+ * be hardwired to 0b, with the exception of the Presence Detect
+ * State bit in the Slot Status register of Downstream Ports,
+ * which must be hardwired to 1b. (PCIe Base Spec 3.0, sec 7.8)
+ */
+ if (pci_is_pcie(dev) && pos == PCI_EXP_SLTSTA &&
+ pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) {
+ *val = PCI_EXP_SLTSTA_PDS;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pcie_capability_read_word);
+
+int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val)
+{
+ int ret;
+
+ *val = 0;
+ if (pos & 3)
+ return -EINVAL;
+
+ if (pcie_capability_reg_implemented(dev, pos)) {
+ ret = pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, val);
+ /*
+ * Reset *val to 0 if pci_read_config_dword() fails, it may
+ * have been written as 0xFFFFFFFF if hardware error happens
+ * during pci_read_config_dword().
+ */
+ if (ret)
+ *val = 0;
+ return ret;
+ }
+
+ if (pci_is_pcie(dev) && pos == PCI_EXP_SLTCTL &&
+ pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) {
+ *val = PCI_EXP_SLTSTA_PDS;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pcie_capability_read_dword);
+
+int pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val)
+{
+ if (pos & 1)
+ return -EINVAL;
+
+ if (!pcie_capability_reg_implemented(dev, pos))
+ return 0;
+
+ return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val);
+}
+EXPORT_SYMBOL_GPL(pcie_capability_write_word);
+
+int pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val)
+{
+ if (pos & 3)
+ return -EINVAL;
+
+ if (!pcie_capability_reg_implemented(dev, pos))
+ return 0;
+
+ return pci_write_config_dword(dev, pci_pcie_cap(dev) + pos, val);
+}
+EXPORT_SYMBOL_GPL(pcie_capability_write_dword);
+
+int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos,
+ u16 clear, u16 set)
+{
+ int ret;
+ u16 val;
+
+ ret = pcie_capability_read_word(dev, pos, &val);
+ if (!ret) {
+ val &= ~clear;
+ val |= set;
+ ret = pcie_capability_write_word(dev, pos, val);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pcie_capability_clear_and_set_word);
+
+int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos,
+ u32 clear, u32 set)
+{
+ int ret;
+ u32 val;
+
+ ret = pcie_capability_read_dword(dev, pos, &val);
+ if (!ret) {
+ val &= ~clear;
+ val |= set;
+ ret = pcie_capability_write_dword(dev, pos, val);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pcie_capability_clear_and_set_dword);
diff --git a/backport/compat/compat-3.8.c b/backport/compat/compat-3.8.c
new file mode 100644
index 00000000..81343234
--- /dev/null
+++ b/backport/compat/compat-3.8.c
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2012 Jiri Kosina
+ * Copyright (c) 2012 Luis R. Rodriguez <mcgrof@do-not-panic.com>
+ *
+ * Compatibility file for Linux wireless for kernels 3.8.
+ *
+ * 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.
+ */
+
+#include <linux/hid.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include "hid-ids.h"
+#include <linux/netdevice.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,8))
+void netdev_set_default_ethtool_ops(struct net_device *dev,
+ const struct ethtool_ops *ops)
+{
+ if (!dev->ethtool_ops)
+ dev->ethtool_ops = ops;
+}
+EXPORT_SYMBOL_GPL(netdev_set_default_ethtool_ops);
+#endif
+
+/* a list of devices that shouldn't be handled by HID core at all */
+static const struct hid_device_id hid_ignore_list[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ADS_TECH, USB_DEVICE_ID_ADS_TECH_RADIO_SI470X) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)},
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)},
+ { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AXENTIA, USB_DEVICE_ID_AXENTIA_FM_RADIO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DEALEXTREAME, USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x000a) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0004) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_SUPER_Q2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_GOGOPEN) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_PENPOWER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GRETAGMACBETH, USB_DEVICE_ID_GRETAGMACBETH_HUEY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_RADIOSHARK) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KWORLD, USB_DEVICE_ID_KWORLD_RADIO_FM700) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_KYE, 0x0058) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYVOLTAGE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYCURRENT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIC) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIB) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOTOR) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOSTANALYSER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOSTANALYSER2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_ABSESP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_AUTODATABUS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MCT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HYBRID) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HEATCONTROL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_BEATPAD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0001) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
+#if defined(CONFIG_MOUSE_SYNAPTICS_USB) || defined(CONFIG_MOUSE_SYNAPTICS_USB_MODULE)
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_INT_TP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_CPAD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_STICK) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_COMP_TP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WTP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DPAD) },
+#endif
+ { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WACOM, HID_ANY_ID) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) },
+ { }
+};
+
+/**
+ * hid_mouse_ignore_list - mouse devices which should not be handled by the hid layer
+ *
+ * There are composite devices for which we want to ignore only a certain
+ * interface. This is a list of devices for which only the mouse interface will
+ * be ignored. This allows a dedicated driver to take care of the interface.
+ */
+static const struct hid_device_id hid_mouse_ignore_list[] = {
+ /* appletouch driver */
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
+ { }
+};
+
+static bool hid_match_one_id(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ return (id->bus == HID_BUS_ANY || id->bus == hdev->bus) &&
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0))
+ (id->group == HID_GROUP_ANY || id->group == hdev->group) &&
+#endif
+ (id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) &&
+ (id->product == HID_ANY_ID || id->product == hdev->product);
+}
+
+const struct hid_device_id *hid_match_id(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ for (; id->bus; id++)
+ if (hid_match_one_id(hdev, id))
+ return id;
+
+ return NULL;
+}
+
+bool hid_ignore(struct hid_device *hdev)
+{
+ if (hdev->quirks & HID_QUIRK_NO_IGNORE)
+ return false;
+ if (hdev->quirks & HID_QUIRK_IGNORE)
+ return true;
+
+ switch (hdev->vendor) {
+ case USB_VENDOR_ID_CODEMERCS:
+ /* ignore all Code Mercenaries IOWarrior devices */
+ if (hdev->product >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST &&
+ hdev->product <= USB_DEVICE_ID_CODEMERCS_IOW_LAST)
+ return true;
+ break;
+ case USB_VENDOR_ID_LOGITECH:
+ if (hdev->product >= USB_DEVICE_ID_LOGITECH_HARMONY_FIRST &&
+ hdev->product <= USB_DEVICE_ID_LOGITECH_HARMONY_LAST)
+ return true;
+ /*
+ * The Keene FM transmitter USB device has the same USB ID as
+ * the Logitech AudioHub Speaker, but it should ignore the hid.
+ * Check if the name is that of the Keene device.
+ * For reference: the name of the AudioHub is
+ * "HOLTEK AudioHub Speaker".
+ */
+ if (hdev->product == USB_DEVICE_ID_LOGITECH_AUDIOHUB &&
+ !strcmp(hdev->name, "HOLTEK B-LINK USB Audio "))
+ return true;
+ break;
+ case USB_VENDOR_ID_SOUNDGRAPH:
+ if (hdev->product >= USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST &&
+ hdev->product <= USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST)
+ return true;
+ break;
+ case USB_VENDOR_ID_HANWANG:
+ if (hdev->product >= USB_DEVICE_ID_HANWANG_TABLET_FIRST &&
+ hdev->product <= USB_DEVICE_ID_HANWANG_TABLET_LAST)
+ return true;
+ break;
+ case USB_VENDOR_ID_JESS:
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
+ if (hdev->product == USB_DEVICE_ID_JESS_YUREX &&
+ hdev->type == HID_TYPE_USBNONE)
+ return true;
+#else
+ if (hdev->product == USB_DEVICE_ID_JESS_YUREX)
+ return true;
+#endif
+ break;
+ case USB_VENDOR_ID_DWAV:
+ /* These are handled by usbtouchscreen. hdev->type is probably
+ * HID_TYPE_USBNONE, but we say !HID_TYPE_USBMOUSE to match
+ * usbtouchscreen. */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
+ if ((hdev->product == USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER ||
+ hdev->product == USB_DEVICE_ID_DWAV_TOUCHCONTROLLER) &&
+ hdev->type != HID_TYPE_USBMOUSE)
+ return true;
+#else
+ if (hdev->product == USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER ||
+ hdev->product == USB_DEVICE_ID_DWAV_TOUCHCONTROLLER)
+ return true;
+#endif
+ break;
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
+ if (hdev->type == HID_TYPE_USBMOUSE &&
+ hid_match_id(hdev, hid_mouse_ignore_list))
+ return true;
+#endif
+
+ return !!hid_match_id(hdev, hid_ignore_list);
+}
+EXPORT_SYMBOL_GPL(hid_ignore);
diff --git a/backport/compat/compat-3.9.c b/backport/compat/compat-3.9.c
new file mode 100644
index 00000000..1f248421
--- /dev/null
+++ b/backport/compat/compat-3.9.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013 Luis R. Rodriguez <mcgrof@do-not-panic.com>
+ *
+ * Compatibility file for Linux wireless for kernels 3.9.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+
+#ifdef __sg_page_iter_next
+
+void __sg_page_iter_start(struct sg_page_iter *piter,
+ struct scatterlist *sglist, unsigned int nents,
+ unsigned long pgoffset)
+{
+ piter->__pg_advance = 0;
+ piter->__nents = nents;
+
+ piter->page = NULL;
+ piter->sg = sglist;
+ piter->sg_pgoffset = pgoffset;
+}
+EXPORT_SYMBOL_GPL(__sg_page_iter_start);
+
+static int sg_page_count(struct scatterlist *sg)
+{
+ return PAGE_ALIGN(sg->offset + sg->length) >> PAGE_SHIFT;
+}
+
+bool __sg_page_iter_next(struct sg_page_iter *piter)
+{
+ if (!piter->__nents || !piter->sg)
+ return false;
+
+ piter->sg_pgoffset += piter->__pg_advance;
+ piter->__pg_advance = 1;
+
+ while (piter->sg_pgoffset >= sg_page_count(piter->sg)) {
+ piter->sg_pgoffset -= sg_page_count(piter->sg);
+ piter->sg = sg_next(piter->sg);
+ if (!--piter->__nents || !piter->sg)
+ return false;
+ }
+ piter->page = nth_page(sg_page(piter->sg), piter->sg_pgoffset);
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(__sg_page_iter_next);
+
+#endif /* __sg_page_iter_next */
diff --git a/backport/compat/compat_atomic.c b/backport/compat/compat_atomic.c
new file mode 100644
index 00000000..b8565aa5
--- /dev/null
+++ b/backport/compat/compat_atomic.c
@@ -0,0 +1,33 @@
+#include <linux/spinlock.h>
+#include <linux/module.h>
+
+#if !((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)) && (defined(CONFIG_UML) || defined(CONFIG_X86))) && !((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) && defined(CONFIG_ARM) && !defined(CONFIG_GENERIC_ATOMIC64))
+
+static DEFINE_SPINLOCK(lock);
+
+long long atomic64_read(const atomic64_t *v)
+{
+ unsigned long flags;
+ long long val;
+
+ spin_lock_irqsave(&lock, flags);
+ val = v->counter;
+ spin_unlock_irqrestore(&lock, flags);
+ return val;
+}
+EXPORT_SYMBOL_GPL(atomic64_read);
+
+long long atomic64_add_return(long long a, atomic64_t *v)
+{
+ unsigned long flags;
+ long long val;
+
+ spin_lock_irqsave(&lock, flags);
+ val = v->counter += a;
+ spin_unlock_irqrestore(&lock, flags);
+ return val;
+}
+EXPORT_SYMBOL_GPL(atomic64_add_return);
+
+#endif
+
diff --git a/backport/compat/compat_firmware_class.c b/backport/compat/compat_firmware_class.c
new file mode 100644
index 00000000..9ea5080e
--- /dev/null
+++ b/backport/compat/compat_firmware_class.c
@@ -0,0 +1,759 @@
+/*
+ * firmware_class.c - Multi purpose firmware loading support
+ *
+ * Copyright (c) 2003 Manuel Estrada Sainz
+ *
+ * Please see Documentation/firmware_class/ for more information.
+ *
+ */
+
+#include <linux/capability.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include <linux/highmem.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+
+#define backport_firmware_to_dev(obj) container_of(obj, struct device, kobj)
+
+MODULE_AUTHOR("Manuel Estrada Sainz");
+MODULE_DESCRIPTION("Multi purpose firmware loading support");
+MODULE_LICENSE("GPL");
+
+/* Builtin firmware support */
+
+//#ifdef CONFIG_FW_LOADER
+#if 0
+
+extern struct builtin_fw __start_builtin_fw[];
+extern struct builtin_fw __end_builtin_fw[];
+
+static bool fw_get_builtin_firmware(struct firmware *fw, const char *name)
+{
+ struct builtin_fw *b_fw;
+
+ for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) {
+ if (strcmp(name, b_fw->name) == 0) {
+ fw->size = b_fw->size;
+ fw->data = b_fw->data;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool fw_is_builtin_firmware(const struct firmware *fw)
+{
+ struct builtin_fw *b_fw;
+
+ for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++)
+ if (fw->data == b_fw->data)
+ return true;
+
+ return false;
+}
+
+#else /* Module case - no builtin firmware support */
+
+static inline bool fw_get_builtin_firmware(struct firmware *fw, const char *name)
+{
+ return false;
+}
+
+static inline bool fw_is_builtin_firmware(const struct firmware *fw)
+{
+ return false;
+}
+#endif
+
+enum {
+ FW_STATUS_LOADING,
+ FW_STATUS_DONE,
+ FW_STATUS_ABORT,
+};
+
+static int loading_timeout = 60; /* In seconds */
+
+/* fw_lock could be moved to 'struct firmware_priv' but since it is just
+ * guarding for corner cases a global lock should be OK */
+static DEFINE_MUTEX(fw_lock);
+
+struct firmware_priv {
+ struct completion completion;
+ struct firmware *fw;
+ unsigned long status;
+ struct page **pages;
+ int nr_pages;
+ int page_array_size;
+ struct timer_list timeout;
+ struct device dev;
+ bool nowait;
+ char fw_id[];
+};
+
+static struct firmware_priv *to_firmware_priv(struct device *dev)
+{
+ return container_of(dev, struct firmware_priv, dev);
+}
+
+static void fw_load_abort(struct firmware_priv *fw_priv)
+{
+ set_bit(FW_STATUS_ABORT, &fw_priv->status);
+ wmb();
+ complete(&fw_priv->completion);
+}
+
+static ssize_t firmware_timeout_show(struct class *class,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", loading_timeout);
+}
+
+/**
+ * firmware_timeout_store - set number of seconds to wait for firmware
+ * @class: device class pointer
+ * @buf: buffer to scan for timeout value
+ * @count: number of bytes in @buf
+ *
+ * Sets the number of seconds to wait for the firmware. Once
+ * this expires an error will be returned to the driver and no
+ * firmware will be provided.
+ *
+ * Note: zero means 'wait forever'.
+ **/
+static ssize_t firmware_timeout_store(struct class *class,
+ const char *buf, size_t count)
+{
+ loading_timeout = simple_strtol(buf, NULL, 10);
+ if (loading_timeout < 0)
+ loading_timeout = 0;
+
+ return count;
+}
+
+static struct class_attribute firmware_class_attrs[] = {
+ __ATTR(timeout, S_IWUSR | S_IRUGO,
+ firmware_timeout_show, firmware_timeout_store),
+ __ATTR_NULL
+};
+
+static void fw_dev_release(struct device *dev)
+{
+ struct firmware_priv *fw_priv = to_firmware_priv(dev);
+ int i;
+
+ for (i = 0; i < fw_priv->nr_pages; i++)
+ __free_page(fw_priv->pages[i]);
+ kfree(fw_priv->pages);
+ kfree(fw_priv);
+
+ module_put(THIS_MODULE);
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
+static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct firmware_priv *fw_priv = to_firmware_priv(dev);
+
+ if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id))
+ return -ENOMEM;
+ if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout))
+ return -ENOMEM;
+ if (add_uevent_var(env, "ASYNC=%d", fw_priv->nowait))
+ return -ENOMEM;
+
+ return 0;
+}
+#else
+static int firmware_uevent(struct device *dev, char **envp,
+ int num_envp, char *buf, int size)
+{
+ struct firmware_priv *fw_priv = to_firmware_priv(dev);
+ int error, len = 0, i = 0;
+
+ error = add_uevent_var(envp, num_envp, &i,
+ buf, size, &len,
+ "FIRMWARE=%s", fw_priv->fw_id);
+ if (error)
+ goto exit;
+
+ error = add_uevent_var(envp, num_envp, &i,
+ buf, size, &len,
+ "TIMEOUT=%i", loading_timeout);
+ if (error)
+ goto exit;
+ error = add_uevent_var(envp, num_envp, &i,
+ buf, size, &len,
+ "ASYNC=%i", fw_priv->nowait);
+ if (error)
+ goto exit;
+
+ return 0;
+exit:
+ envp[i] = NULL;
+ return error;
+}
+#endif
+
+static struct class firmware_class = {
+ .name = "compat_firmware",
+ .class_attrs = firmware_class_attrs,
+ .dev_uevent = firmware_uevent,
+ .dev_release = fw_dev_release,
+};
+
+static ssize_t firmware_loading_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct firmware_priv *fw_priv = to_firmware_priv(dev);
+ int loading = test_bit(FW_STATUS_LOADING, &fw_priv->status);
+
+ return sprintf(buf, "%d\n", loading);
+}
+
+static void firmware_free_data(const struct firmware *fw)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
+ int i;
+ vunmap(fw->data);
+ if (fw->pages) {
+ for (i = 0; i < PFN_UP(fw->size); i++)
+ __free_page(fw->pages[i]);
+ kfree(fw->pages);
+ }
+#else
+ vunmap(fw->data);
+#endif
+}
+
+/* Some architectures don't have PAGE_KERNEL_RO */
+#ifndef PAGE_KERNEL_RO
+#define PAGE_KERNEL_RO PAGE_KERNEL
+#endif
+/**
+ * firmware_loading_store - set value in the 'loading' control file
+ * @dev: device pointer
+ * @buf: buffer to scan for loading control value
+ * @count: number of bytes in @buf
+ *
+ * The relevant values are:
+ *
+ * 1: Start a load, discarding any previous partial load.
+ * 0: Conclude the load and hand the data to the driver code.
+ * -1: Conclude the load with an error and discard any written data.
+ **/
+static ssize_t firmware_loading_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct firmware_priv *fw_priv = to_firmware_priv(dev);
+ int loading = simple_strtol(buf, NULL, 10);
+ int i;
+
+ switch (loading) {
+ case 1:
+ mutex_lock(&fw_lock);
+ if (!fw_priv->fw) {
+ mutex_unlock(&fw_lock);
+ break;
+ }
+ firmware_free_data(fw_priv->fw);
+ memset(fw_priv->fw, 0, sizeof(struct firmware));
+ /* If the pages are not owned by 'struct firmware' */
+ for (i = 0; i < fw_priv->nr_pages; i++)
+ __free_page(fw_priv->pages[i]);
+ kfree(fw_priv->pages);
+ fw_priv->pages = NULL;
+ fw_priv->page_array_size = 0;
+ fw_priv->nr_pages = 0;
+ set_bit(FW_STATUS_LOADING, &fw_priv->status);
+ mutex_unlock(&fw_lock);
+ break;
+ case 0:
+ if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) {
+ vunmap(fw_priv->fw->data);
+ fw_priv->fw->data = vmap(fw_priv->pages,
+ fw_priv->nr_pages,
+ 0, PAGE_KERNEL_RO);
+ if (!fw_priv->fw->data) {
+ dev_err(dev, "%s: vmap() failed\n", __func__);
+ goto err;
+ }
+ /* Pages are now owned by 'struct firmware' */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
+ fw_priv->fw->pages = fw_priv->pages;
+ fw_priv->pages = NULL;
+#endif
+
+ fw_priv->page_array_size = 0;
+ fw_priv->nr_pages = 0;
+ complete(&fw_priv->completion);
+ clear_bit(FW_STATUS_LOADING, &fw_priv->status);
+ break;
+ }
+ /* fallthrough */
+ default:
+ dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading);
+ /* fallthrough */
+ case -1:
+ err:
+ fw_load_abort(fw_priv);
+ break;
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
+
+#if defined(CONFIG_COMPAT_FIRMWARE_DATA_RW_NEEDS_FILP)
+static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t offset, size_t count)
+#else
+static ssize_t firmware_data_read(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t offset, size_t count)
+#endif
+{
+ struct device *dev = backport_firmware_to_dev(kobj);
+ struct firmware_priv *fw_priv = to_firmware_priv(dev);
+ struct firmware *fw;
+ ssize_t ret_count;
+
+ mutex_lock(&fw_lock);
+ fw = fw_priv->fw;
+ if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
+ ret_count = -ENODEV;
+ goto out;
+ }
+ if (offset > fw->size) {
+ ret_count = 0;
+ goto out;
+ }
+ if (count > fw->size - offset)
+ count = fw->size - offset;
+
+ ret_count = count;
+
+ while (count) {
+ void *page_data;
+ int page_nr = offset >> PAGE_SHIFT;
+ int page_ofs = offset & (PAGE_SIZE-1);
+ int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
+
+ page_data = kmap(fw_priv->pages[page_nr]);
+
+ memcpy(buffer, page_data + page_ofs, page_cnt);
+
+ kunmap(fw_priv->pages[page_nr]);
+ buffer += page_cnt;
+ offset += page_cnt;
+ count -= page_cnt;
+ }
+out:
+ mutex_unlock(&fw_lock);
+ return ret_count;
+}
+
+static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
+{
+ int pages_needed = ALIGN(min_size, PAGE_SIZE) >> PAGE_SHIFT;
+
+ /* If the array of pages is too small, grow it... */
+ if (fw_priv->page_array_size < pages_needed) {
+ int new_array_size = max(pages_needed,
+ fw_priv->page_array_size * 2);
+ struct page **new_pages;
+
+ new_pages = kmalloc(new_array_size * sizeof(void *),
+ GFP_KERNEL);
+ if (!new_pages) {
+ fw_load_abort(fw_priv);
+ return -ENOMEM;
+ }
+ memcpy(new_pages, fw_priv->pages,
+ fw_priv->page_array_size * sizeof(void *));
+ memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
+ (new_array_size - fw_priv->page_array_size));
+ kfree(fw_priv->pages);
+ fw_priv->pages = new_pages;
+ fw_priv->page_array_size = new_array_size;
+ }
+
+ while (fw_priv->nr_pages < pages_needed) {
+ fw_priv->pages[fw_priv->nr_pages] =
+ alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+
+ if (!fw_priv->pages[fw_priv->nr_pages]) {
+ fw_load_abort(fw_priv);
+ return -ENOMEM;
+ }
+ fw_priv->nr_pages++;
+ }
+ return 0;
+}
+
+/**
+ * firmware_data_write - write method for firmware
+ * @kobj: kobject for the device
+ * @bin_attr: bin_attr structure
+ * @buffer: buffer being written
+ * @offset: buffer offset for write in total data store area
+ * @count: buffer size
+ *
+ * Data written to the 'data' attribute will be later handed to
+ * the driver as a firmware image.
+ **/
+#if defined(CONFIG_COMPAT_FIRMWARE_DATA_RW_NEEDS_FILP)
+static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t offset, size_t count)
+#else
+static ssize_t firmware_data_write(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t offset, size_t count)
+#endif
+{
+ struct device *dev = backport_firmware_to_dev(kobj);
+ struct firmware_priv *fw_priv = to_firmware_priv(dev);
+ struct firmware *fw;
+ ssize_t retval;
+
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ mutex_lock(&fw_lock);
+ fw = fw_priv->fw;
+ if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
+ retval = -ENODEV;
+ goto out;
+ }
+ retval = fw_realloc_buffer(fw_priv, offset + count);
+ if (retval)
+ goto out;
+
+ retval = count;
+
+ while (count) {
+ void *page_data;
+ int page_nr = offset >> PAGE_SHIFT;
+ int page_ofs = offset & (PAGE_SIZE - 1);
+ int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
+
+ page_data = kmap(fw_priv->pages[page_nr]);
+
+ memcpy(page_data + page_ofs, buffer, page_cnt);
+
+ kunmap(fw_priv->pages[page_nr]);
+ buffer += page_cnt;
+ offset += page_cnt;
+ count -= page_cnt;
+ }
+
+ fw->size = max_t(size_t, offset, fw->size);
+out:
+ mutex_unlock(&fw_lock);
+ return retval;
+}
+
+static struct bin_attribute firmware_attr_data = {
+ .attr = { .name = "data", .mode = 0644 },
+ .size = 0,
+ .read = firmware_data_read,
+ .write = firmware_data_write,
+};
+
+static void firmware_class_timeout(u_long data)
+{
+ struct firmware_priv *fw_priv = (struct firmware_priv *) data;
+
+ fw_load_abort(fw_priv);
+}
+
+static struct firmware_priv *
+fw_create_instance(struct firmware *firmware, const char *fw_name,
+ struct device *device, bool uevent, bool nowait)
+{
+ struct firmware_priv *fw_priv;
+ struct device *f_dev;
+ int error;
+
+ fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
+ if (!fw_priv) {
+ dev_err(device, "%s: kmalloc failed\n", __func__);
+ error = -ENOMEM;
+ goto err_out;
+ }
+
+ fw_priv->fw = firmware;
+ fw_priv->nowait = nowait;
+ strcpy(fw_priv->fw_id, fw_name);
+ init_completion(&fw_priv->completion);
+ setup_timer(&fw_priv->timeout,
+ firmware_class_timeout, (u_long) fw_priv);
+
+ f_dev = &fw_priv->dev;
+
+ device_initialize(f_dev);
+ dev_set_name(f_dev, "%s", dev_name(device));
+ f_dev->parent = device;
+ f_dev->class = &firmware_class;
+
+ dev_set_uevent_suppress(f_dev, true);
+
+ /* Need to pin this module until class device is destroyed */
+ __module_get(THIS_MODULE);
+
+ error = device_add(f_dev);
+ if (error) {
+ dev_err(device, "%s: device_register failed\n", __func__);
+ goto err_put_dev;
+ }
+
+ error = device_create_bin_file(f_dev, &firmware_attr_data);
+ if (error) {
+ dev_err(device, "%s: sysfs_create_bin_file failed\n", __func__);
+ goto err_del_dev;
+ }
+
+ error = device_create_file(f_dev, &dev_attr_loading);
+ if (error) {
+ dev_err(device, "%s: device_create_file failed\n", __func__);
+ goto err_del_bin_attr;
+ }
+
+ if (uevent)
+ dev_set_uevent_suppress(f_dev, false);
+
+ return fw_priv;
+
+err_del_bin_attr:
+ device_remove_bin_file(f_dev, &firmware_attr_data);
+err_del_dev:
+ device_del(f_dev);
+err_put_dev:
+ put_device(f_dev);
+err_out:
+ return ERR_PTR(error);
+}
+
+static void fw_destroy_instance(struct firmware_priv *fw_priv)
+{
+ struct device *f_dev = &fw_priv->dev;
+
+ device_remove_file(f_dev, &dev_attr_loading);
+ device_remove_bin_file(f_dev, &firmware_attr_data);
+ device_unregister(f_dev);
+}
+
+static int _request_firmware(const struct firmware **firmware_p,
+ const char *name, struct device *device,
+ bool uevent, bool nowait)
+{
+ struct firmware_priv *fw_priv;
+ struct firmware *firmware;
+ int retval = 0;
+
+ if (!firmware_p)
+ return -EINVAL;
+
+ *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
+ if (!firmware) {
+ dev_err(device, "%s: kmalloc(struct firmware) failed\n",
+ __func__);
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ if (fw_get_builtin_firmware(firmware, name)) {
+ dev_dbg(device, "firmware: using built-in firmware %s\n", name);
+ return 0;
+ }
+
+ if (uevent)
+ dev_dbg(device, "firmware: requesting %s\n", name);
+
+ fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
+ if (IS_ERR(fw_priv)) {
+ retval = PTR_ERR(fw_priv);
+ goto out;
+ }
+
+ if (uevent) {
+ if (loading_timeout > 0)
+ mod_timer(&fw_priv->timeout,
+ round_jiffies_up(jiffies +
+ loading_timeout * HZ));
+
+ kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
+ }
+
+ wait_for_completion(&fw_priv->completion);
+
+ set_bit(FW_STATUS_DONE, &fw_priv->status);
+ del_timer_sync(&fw_priv->timeout);
+
+ mutex_lock(&fw_lock);
+ if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status))
+ retval = -ENOENT;
+ fw_priv->fw = NULL;
+ mutex_unlock(&fw_lock);
+
+ fw_destroy_instance(fw_priv);
+
+out:
+ if (retval) {
+ release_firmware(firmware);
+ *firmware_p = NULL;
+ }
+
+ return retval;
+}
+
+/**
+ * request_firmware: - send firmware request and wait for it
+ * @firmware_p: pointer to firmware image
+ * @name: name of firmware file
+ * @device: device for which firmware is being loaded
+ *
+ * @firmware_p will be used to return a firmware image by the name
+ * of @name for device @device.
+ *
+ * Should be called from user context where sleeping is allowed.
+ *
+ * @name will be used as $FIRMWARE in the uevent environment and
+ * should be distinctive enough not to be confused with any other
+ * firmware image for this or any other device.
+ **/
+int
+request_firmware(const struct firmware **firmware_p, const char *name,
+ struct device *device)
+{
+ int uevent = 1;
+ return _request_firmware(firmware_p, name, device, uevent, false);
+}
+
+/**
+ * release_firmware: - release the resource associated with a firmware image
+ * @fw: firmware resource to release
+ **/
+void release_firmware(const struct firmware *fw)
+{
+ if (fw) {
+ if (!fw_is_builtin_firmware(fw))
+ firmware_free_data(fw);
+ kfree(fw);
+ }
+}
+
+/* Async support */
+struct firmware_work {
+ struct work_struct work;
+ struct module *module;
+ const char *name;
+ struct device *device;
+ void *context;
+ void (*cont)(const struct firmware *fw, void *context);
+ int uevent;
+};
+
+static int request_firmware_work_func(void *arg)
+{
+ struct firmware_work *fw_work = arg;
+ const struct firmware *fw;
+ int ret;
+
+ if (!arg) {
+ WARN_ON(1);
+ return 0;
+ }
+
+ ret = _request_firmware(&fw, fw_work->name, fw_work->device,
+ fw_work->uevent, true);
+ fw_work->cont(fw, fw_work->context);
+
+ module_put(fw_work->module);
+ kfree(fw_work);
+
+ return ret;
+}
+
+/**
+ * request_firmware_nowait - asynchronous version of request_firmware
+ * @module: module requesting the firmware
+ * @uevent: sends uevent to copy the firmware image if this flag
+ * is non-zero else the firmware copy must be done manually.
+ * @name: name of firmware file
+ * @device: device for which firmware is being loaded
+ * @gfp: allocation flags
+ * @context: will be passed over to @cont, and
+ * @fw may be %NULL if firmware request fails.
+ * @cont: function will be called asynchronously when the firmware
+ * request is over.
+ *
+ * Asynchronous variant of request_firmware() for user contexts where
+ * it is not possible to sleep for long time. It can't be called
+ * in atomic contexts.
+ **/
+int
+request_firmware_nowait(
+ struct module *module, int uevent,
+ const char *name, struct device *device, gfp_t gfp, void *context,
+ void (*cont)(const struct firmware *fw, void *context))
+{
+ struct task_struct *task;
+ struct firmware_work *fw_work;
+
+ fw_work = kzalloc(sizeof (struct firmware_work), gfp);
+ if (!fw_work)
+ return -ENOMEM;
+
+ fw_work->module = module;
+ fw_work->name = name;
+ fw_work->device = device;
+ fw_work->context = context;
+ fw_work->cont = cont;
+ fw_work->uevent = uevent;
+
+ if (!try_module_get(module)) {
+ kfree(fw_work);
+ return -EFAULT;
+ }
+
+ task = kthread_run(request_firmware_work_func, fw_work,
+ "firmware/%s", name);
+ if (IS_ERR(task)) {
+ fw_work->cont(NULL, fw_work->context);
+ module_put(fw_work->module);
+ kfree(fw_work);
+ return PTR_ERR(task);
+ }
+
+ return 0;
+}
+
+static int __init firmware_class_init(void)
+{
+ return class_register(&firmware_class);
+}
+
+static void __exit firmware_class_exit(void)
+{
+ class_unregister(&firmware_class);
+}
+
+fs_initcall(firmware_class_init);
+module_exit(firmware_class_exit);
+
+EXPORT_SYMBOL_GPL(release_firmware);
+EXPORT_SYMBOL_GPL(request_firmware);
+EXPORT_SYMBOL_GPL(request_firmware_nowait);
diff --git a/backport/compat/cordic.c b/backport/compat/cordic.c
new file mode 100644
index 00000000..a6340b6a
--- /dev/null
+++ b/backport/compat/cordic.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/module.h>
+#include <linux/cordic.h>
+
+#define CORDIC_ANGLE_GEN 39797
+#define CORDIC_PRECISION_SHIFT 16
+#define CORDIC_NUM_ITER (CORDIC_PRECISION_SHIFT + 2)
+
+#define FIXED(X) ((s32)((X) << CORDIC_PRECISION_SHIFT))
+#define FLOAT(X) (((X) >= 0) \
+ ? ((((X) >> (CORDIC_PRECISION_SHIFT - 1)) + 1) >> 1) \
+ : -((((-(X)) >> (CORDIC_PRECISION_SHIFT - 1)) + 1) >> 1))
+
+static const s32 arctan_table[] = {
+ 2949120,
+ 1740967,
+ 919879,
+ 466945,
+ 234379,
+ 117304,
+ 58666,
+ 29335,
+ 14668,
+ 7334,
+ 3667,
+ 1833,
+ 917,
+ 458,
+ 229,
+ 115,
+ 57,
+ 29
+};
+
+/*
+ * cordic_calc_iq() - calculates the i/q coordinate for given angle
+ *
+ * theta: angle in degrees for which i/q coordinate is to be calculated
+ * coord: function output parameter holding the i/q coordinate
+ */
+struct cordic_iq cordic_calc_iq(s32 theta)
+{
+ struct cordic_iq coord;
+ s32 angle, valtmp;
+ unsigned iter;
+ int signx = 1;
+ int signtheta;
+
+ coord.i = CORDIC_ANGLE_GEN;
+ coord.q = 0;
+ angle = 0;
+
+ theta = FIXED(theta);
+ signtheta = (theta < 0) ? -1 : 1;
+ theta = ((theta + FIXED(180) * signtheta) % FIXED(360)) -
+ FIXED(180) * signtheta;
+
+ if (FLOAT(theta) > 90) {
+ theta -= FIXED(180);
+ signx = -1;
+ } else if (FLOAT(theta) < -90) {
+ theta += FIXED(180);
+ signx = -1;
+ }
+
+ for (iter = 0; iter < CORDIC_NUM_ITER; iter++) {
+ if (theta > angle) {
+ valtmp = coord.i - (coord.q >> iter);
+ coord.q += (coord.i >> iter);
+ angle += arctan_table[iter];
+ } else {
+ valtmp = coord.i + (coord.q >> iter);
+ coord.q -= (coord.i >> iter);
+ angle -= arctan_table[iter];
+ }
+ coord.i = valtmp;
+ }
+
+ coord.i *= signx;
+ coord.q *= signx;
+ return coord;
+}
+EXPORT_SYMBOL_GPL(cordic_calc_iq);
+
+MODULE_DESCRIPTION("Cordic functions");
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/backport/compat/crc8.c b/backport/compat/crc8.c
new file mode 100644
index 00000000..5878171c
--- /dev/null
+++ b/backport/compat/crc8.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#undef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/crc8.h>
+#include <linux/printk.h>
+
+/*
+ * crc8_populate_msb - fill crc table for given polynomial in reverse bit order.
+ *
+ * table: table to be filled.
+ * polynomial: polynomial for which table is to be filled.
+ */
+void crc8_populate_msb(u8 table[CRC8_TABLE_SIZE], u8 polynomial)
+{
+ int i, j;
+ const u8 msbit = 0x80;
+ u8 t = msbit;
+
+ table[0] = 0;
+
+ for (i = 1; i < CRC8_TABLE_SIZE; i *= 2) {
+ t = (t << 1) ^ (t & msbit ? polynomial : 0);
+ for (j = 0; j < i; j++)
+ table[i+j] = table[j] ^ t;
+ }
+}
+EXPORT_SYMBOL_GPL(crc8_populate_msb);
+
+/*
+ * crc8_populate_lsb - fill crc table for given polynomial in regular bit order.
+ *
+ * table: table to be filled.
+ * polynomial: polynomial for which table is to be filled.
+ */
+void crc8_populate_lsb(u8 table[CRC8_TABLE_SIZE], u8 polynomial)
+{
+ int i, j;
+ u8 t = 1;
+
+ table[0] = 0;
+
+ for (i = (CRC8_TABLE_SIZE >> 1); i; i >>= 1) {
+ t = (t >> 1) ^ (t & 1 ? polynomial : 0);
+ for (j = 0; j < CRC8_TABLE_SIZE; j += 2*i)
+ table[i+j] = table[j] ^ t;
+ }
+}
+EXPORT_SYMBOL_GPL(crc8_populate_lsb);
+
+/*
+ * crc8 - calculate a crc8 over the given input data.
+ *
+ * table: crc table used for calculation.
+ * pdata: pointer to data buffer.
+ * nbytes: number of bytes in data buffer.
+ * crc: previous returned crc8 value.
+ */
+u8 crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes, u8 crc)
+{
+ /* loop over the buffer data */
+ while (nbytes-- > 0)
+ crc = table[(crc ^ *pdata++) & 0xff];
+
+ return crc;
+}
+EXPORT_SYMBOL_GPL(crc8);
+
+MODULE_DESCRIPTION("CRC8 (by Williams, Ross N.) function");
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/backport/compat/flow_dissector.c b/backport/compat/flow_dissector.c
new file mode 100644
index 00000000..7dd7ec19
--- /dev/null
+++ b/backport/compat/flow_dissector.c
@@ -0,0 +1,143 @@
+#include <linux/skbuff.h>
+#include <linux/export.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/if_vlan.h>
+#include <net/ip.h>
+#include <linux/if_tunnel.h>
+#include <linux/if_pppox.h>
+#include <linux/ppp_defs.h>
+#include <net/flow_keys.h>
+
+/* copy saddr & daddr, possibly using 64bit load/store
+ * Equivalent to : flow->src = iph->saddr;
+ * flow->dst = iph->daddr;
+ */
+static void iph_to_flow_copy_addrs(struct flow_keys *flow, const struct iphdr *iph)
+{
+ BUILD_BUG_ON(offsetof(typeof(*flow), dst) !=
+ offsetof(typeof(*flow), src) + sizeof(flow->src));
+ memcpy(&flow->src, &iph->saddr, sizeof(flow->src) + sizeof(flow->dst));
+}
+
+bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
+{
+ int poff, nhoff = skb_network_offset(skb);
+ u8 ip_proto;
+ __be16 proto = skb->protocol;
+
+ memset(flow, 0, sizeof(*flow));
+
+again:
+ switch (proto) {
+ case __constant_htons(ETH_P_IP): {
+ const struct iphdr *iph;
+ struct iphdr _iph;
+ip:
+ iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
+ if (!iph)
+ return false;
+
+ if (ip_is_fragment(iph))
+ ip_proto = 0;
+ else
+ ip_proto = iph->protocol;
+ iph_to_flow_copy_addrs(flow, iph);
+ nhoff += iph->ihl * 4;
+ break;
+ }
+ case __constant_htons(ETH_P_IPV6): {
+ const struct ipv6hdr *iph;
+ struct ipv6hdr _iph;
+ipv6:
+ iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
+ if (!iph)
+ return false;
+
+ ip_proto = iph->nexthdr;
+ flow->src = iph->saddr.s6_addr32[3];
+ flow->dst = iph->daddr.s6_addr32[3];
+ nhoff += sizeof(struct ipv6hdr);
+ break;
+ }
+ case __constant_htons(ETH_P_8021Q): {
+ const struct vlan_hdr *vlan;
+ struct vlan_hdr _vlan;
+
+ vlan = skb_header_pointer(skb, nhoff, sizeof(_vlan), &_vlan);
+ if (!vlan)
+ return false;
+
+ proto = vlan->h_vlan_encapsulated_proto;
+ nhoff += sizeof(*vlan);
+ goto again;
+ }
+ case __constant_htons(ETH_P_PPP_SES): {
+ struct {
+ struct pppoe_hdr hdr;
+ __be16 proto;
+ } *hdr, _hdr;
+ hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr);
+ if (!hdr)
+ return false;
+ proto = hdr->proto;
+ nhoff += PPPOE_SES_HLEN;
+ switch (proto) {
+ case __constant_htons(PPP_IP):
+ goto ip;
+ case __constant_htons(PPP_IPV6):
+ goto ipv6;
+ default:
+ return false;
+ }
+ }
+ default:
+ return false;
+ }
+
+ switch (ip_proto) {
+ case IPPROTO_GRE: {
+ struct gre_hdr {
+ __be16 flags;
+ __be16 proto;
+ } *hdr, _hdr;
+
+ hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr);
+ if (!hdr)
+ return false;
+ /*
+ * Only look inside GRE if version zero and no
+ * routing
+ */
+ if (!(hdr->flags & (GRE_VERSION|GRE_ROUTING))) {
+ proto = hdr->proto;
+ nhoff += 4;
+ if (hdr->flags & GRE_CSUM)
+ nhoff += 4;
+ if (hdr->flags & GRE_KEY)
+ nhoff += 4;
+ if (hdr->flags & GRE_SEQ)
+ nhoff += 4;
+ goto again;
+ }
+ break;
+ }
+ case IPPROTO_IPIP:
+ goto again;
+ default:
+ break;
+ }
+
+ flow->ip_proto = ip_proto;
+ poff = proto_ports_offset(ip_proto);
+ if (poff >= 0) {
+ __be32 *ports, _ports;
+
+ nhoff += poff;
+ ports = skb_header_pointer(skb, nhoff, sizeof(_ports), &_ports);
+ if (ports)
+ flow->ports = *ports;
+ }
+
+ return true;
+}
diff --git a/backport/compat/hid-ids.h b/backport/compat/hid-ids.h
new file mode 100644
index 00000000..c147dc06
--- /dev/null
+++ b/backport/compat/hid-ids.h
@@ -0,0 +1,866 @@
+/*
+ * USB HID quirks support for Linux
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#ifndef HID_IDS_H_FILE
+#define HID_IDS_H_FILE
+
+#define USB_VENDOR_ID_3M 0x0596
+#define USB_DEVICE_ID_3M1968 0x0500
+#define USB_DEVICE_ID_3M2256 0x0502
+#define USB_DEVICE_ID_3M3266 0x0506
+
+#define USB_VENDOR_ID_A4TECH 0x09da
+#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006
+#define USB_DEVICE_ID_A4TECH_X5_005D 0x000a
+#define USB_DEVICE_ID_A4TECH_RP_649 0x001a
+
+#define USB_VENDOR_ID_AASHIMA 0x06d6
+#define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025
+#define USB_DEVICE_ID_AASHIMA_PREDATOR 0x0026
+
+#define USB_VENDOR_ID_ACECAD 0x0460
+#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004
+#define USB_DEVICE_ID_ACECAD_302 0x0008
+
+#define USB_VENDOR_ID_ACRUX 0x1a34
+
+#define USB_VENDOR_ID_ACTIONSTAR 0x2101
+#define USB_DEVICE_ID_ACTIONSTAR_1011 0x1011
+
+#define USB_VENDOR_ID_ADS_TECH 0x06e1
+#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155
+
+#define USB_VENDOR_ID_AFATECH 0x15a4
+#define USB_DEVICE_ID_AFATECH_AF9016 0x9016
+
+#define USB_VENDOR_ID_AIPTEK 0x08ca
+#define USB_DEVICE_ID_AIPTEK_01 0x0001
+#define USB_DEVICE_ID_AIPTEK_10 0x0010
+#define USB_DEVICE_ID_AIPTEK_20 0x0020
+#define USB_DEVICE_ID_AIPTEK_21 0x0021
+#define USB_DEVICE_ID_AIPTEK_22 0x0022
+#define USB_DEVICE_ID_AIPTEK_23 0x0023
+#define USB_DEVICE_ID_AIPTEK_24 0x0024
+
+#define USB_VENDOR_ID_AIRCABLE 0x16CA
+#define USB_DEVICE_ID_AIRCABLE1 0x1502
+
+#define USB_VENDOR_ID_AIREN 0x1a2c
+#define USB_DEVICE_ID_AIREN_SLIMPLUS 0x0002
+
+#define USB_VENDOR_ID_ALCOR 0x058f
+#define USB_DEVICE_ID_ALCOR_USBRS232 0x9720
+
+#define USB_VENDOR_ID_ALPS 0x0433
+#define USB_DEVICE_ID_IBM_GAMEPAD 0x1101
+
+#define USB_VENDOR_ID_APPLE 0x05ac
+#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
+#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d
+#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f
+#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214
+#define USB_DEVICE_ID_APPLE_GEYSER_ISO 0x0215
+#define USB_DEVICE_ID_APPLE_GEYSER_JIS 0x0216
+#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI 0x0217
+#define USB_DEVICE_ID_APPLE_GEYSER3_ISO 0x0218
+#define USB_DEVICE_ID_APPLE_GEYSER3_JIS 0x0219
+#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI 0x021a
+#define USB_DEVICE_ID_APPLE_GEYSER4_ISO 0x021b
+#define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c
+#define USB_DEVICE_ID_APPLE_ALU_MINI_ANSI 0x021d
+#define USB_DEVICE_ID_APPLE_ALU_MINI_ISO 0x021e
+#define USB_DEVICE_ID_APPLE_ALU_MINI_JIS 0x021f
+#define USB_DEVICE_ID_APPLE_ALU_ANSI 0x0220
+#define USB_DEVICE_ID_APPLE_ALU_ISO 0x0221
+#define USB_DEVICE_ID_APPLE_ALU_JIS 0x0222
+#define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI 0x0223
+#define USB_DEVICE_ID_APPLE_WELLSPRING_ISO 0x0224
+#define USB_DEVICE_ID_APPLE_WELLSPRING_JIS 0x0225
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI 0x0229
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO 0x022a
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS 0x022b
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI 0x022c
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO 0x022d
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS 0x022e
+#define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230
+#define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231
+#define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232
+#define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236
+#define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237
+#define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI 0x023f
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ISO 0x0240
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_JIS 0x0241
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO 0x0243
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS 0x0244
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247
+#define USB_DEVICE_ID_APPLE_ALU_REVB_ANSI 0x024f
+#define USB_DEVICE_ID_APPLE_ALU_REVB_ISO 0x0250
+#define USB_DEVICE_ID_APPLE_ALU_REVB_JIS 0x0251
+#define USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI 0x0252
+#define USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO 0x0253
+#define USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS 0x0254
+#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI 0x0259
+#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO 0x025a
+#define USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS 0x025b
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI 0x0249
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO 0x024a
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS 0x024b
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI 0x024c
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO 0x024d
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_JIS 0x024e
+#define USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI 0x0262
+#define USB_DEVICE_ID_APPLE_WELLSPRING7_ISO 0x0263
+#define USB_DEVICE_ID_APPLE_WELLSPRING7_JIS 0x0264
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI 0x0255
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
+#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
+#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241
+#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
+
+#define USB_VENDOR_ID_ASUS 0x0486
+#define USB_DEVICE_ID_ASUS_T91MT 0x0185
+#define USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO 0x0186
+
+#define USB_VENDOR_ID_ASUSTEK 0x0b05
+#define USB_DEVICE_ID_ASUSTEK_LCM 0x1726
+#define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b
+
+#define USB_VENDOR_ID_ATEN 0x0557
+#define USB_DEVICE_ID_ATEN_UC100KM 0x2004
+#define USB_DEVICE_ID_ATEN_CS124U 0x2202
+#define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204
+#define USB_DEVICE_ID_ATEN_4PORTKVM 0x2205
+#define USB_DEVICE_ID_ATEN_4PORTKVMC 0x2208
+
+#define USB_VENDOR_ID_ATMEL 0x03eb
+#define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c
+#define USB_DEVICE_ID_ATMEL_MXT_DIGITIZER 0x2118
+
+#define USB_VENDOR_ID_AUREAL 0x0755
+#define USB_DEVICE_ID_AUREAL_W01RN 0x2626
+
+#define USB_VENDOR_ID_AVERMEDIA 0x07ca
+#define USB_DEVICE_ID_AVER_FM_MR800 0xb800
+
+#define USB_VENDOR_ID_AXENTIA 0x12cf
+#define USB_DEVICE_ID_AXENTIA_FM_RADIO 0x7111
+
+#define USB_VENDOR_ID_BAANTO 0x2453
+#define USB_DEVICE_ID_BAANTO_MT_190W2 0x0100
+
+#define USB_VENDOR_ID_BELKIN 0x050d
+#define USB_DEVICE_ID_FLIP_KVM 0x3201
+
+#define USB_VENDOR_ID_BERKSHIRE 0x0c98
+#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
+
+#define USB_VENDOR_ID_BTC 0x046e
+#define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578
+#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577
+
+#define USB_VENDOR_ID_CANDO 0x2087
+#define USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH 0x0703
+#define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01
+#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1 0x0a02
+#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6 0x0b03
+#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6 0x0f01
+
+#define USB_VENDOR_ID_CH 0x068e
+#define USB_DEVICE_ID_CH_PRO_THROTTLE 0x00f1
+#define USB_DEVICE_ID_CH_PRO_PEDALS 0x00f2
+#define USB_DEVICE_ID_CH_FIGHTERSTICK 0x00f3
+#define USB_DEVICE_ID_CH_COMBATSTICK 0x00f4
+#define USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE 0x0051
+#define USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE 0x00ff
+#define USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK 0x00d3
+#define USB_DEVICE_ID_CH_AXIS_295 0x001c
+
+#define USB_VENDOR_ID_CHERRY 0x046a
+#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023
+#define USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR 0x0027
+
+#define USB_VENDOR_ID_CHIC 0x05fe
+#define USB_DEVICE_ID_CHIC_GAMEPAD 0x0014
+
+#define USB_VENDOR_ID_CHICONY 0x04f2
+#define USB_DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418
+#define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d
+#define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618
+#define USB_DEVICE_ID_CHICONY_WIRELESS2 0x1123
+#define USB_DEVICE_ID_CHICONY_AK1D 0x1125
+
+#define USB_VENDOR_ID_CHUNGHWAT 0x2247
+#define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH 0x0001
+
+#define USB_VENDOR_ID_CIDC 0x1677
+
+#define USB_VENDOR_ID_CMEDIA 0x0d8c
+#define USB_DEVICE_ID_CM109 0x000e
+
+#define USB_VENDOR_ID_CODEMERCS 0x07c0
+#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500
+#define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff
+
+#define USB_VENDOR_ID_CREATIVELABS 0x041e
+#define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801
+
+#define USB_VENDOR_ID_CVTOUCH 0x1ff7
+#define USB_DEVICE_ID_CVTOUCH_SCREEN 0x0013
+
+#define USB_VENDOR_ID_CYGNAL 0x10c4
+#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a
+
+#define USB_VENDOR_ID_CYPRESS 0x04b4
+#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001
+#define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500
+#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417
+#define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61
+#define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64
+#define USB_DEVICE_ID_CYPRESS_BARCODE_3 0xbca1
+#define USB_DEVICE_ID_CYPRESS_BARCODE_4 0xed81
+#define USB_DEVICE_ID_CYPRESS_TRUETOUCH 0xc001
+
+#define USB_VENDOR_ID_DEALEXTREAME 0x10c5
+#define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a
+
+#define USB_VENDOR_ID_DELORME 0x1163
+#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
+#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200
+
+#define USB_VENDOR_ID_DMI 0x0c0b
+#define USB_DEVICE_ID_DMI_ENC 0x5fab
+
+#define USB_VENDOR_ID_DRAGONRISE 0x0079
+
+#define USB_VENDOR_ID_DWAV 0x0eef
+#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001
+#define USB_DEVICE_ID_DWAV_TOUCHCONTROLLER 0x0002
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D 0x480d
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E 0x480e
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207 0x7207
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C 0x720c
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224 0x7224
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_722A 0x722A
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E 0x725e
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262 0x7262
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B 0x726b
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA 0x72aa
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1 0x72a1
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA 0x72fa
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302 0x7302
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349 0x7349
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7 0x73f7
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224 0x7224
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0 0x72d0
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4 0x72c4
+
+#define USB_VENDOR_ID_ELECOM 0x056e
+#define USB_DEVICE_ID_ELECOM_BM084 0x0061
+
+#define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34
+
+#define USB_VENDOR_ID_ELO 0x04E7
+#define USB_DEVICE_ID_ELO_TS2515 0x0022
+#define USB_DEVICE_ID_ELO_TS2700 0x0020
+
+#define USB_VENDOR_ID_EMS 0x2006
+#define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118
+
+#define USB_VENDOR_ID_FLATFROG 0x25b5
+#define USB_DEVICE_ID_MULTITOUCH_3200 0x0002
+
+#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
+#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
+
+#define USB_VENDOR_ID_ETT 0x0664
+#define USB_DEVICE_ID_TC5UH 0x0309
+#define USB_DEVICE_ID_TC4UM 0x0306
+
+#define USB_VENDOR_ID_ETURBOTOUCH 0x22b9
+#define USB_DEVICE_ID_ETURBOTOUCH 0x0006
+
+#define USB_VENDOR_ID_EZKEY 0x0518
+#define USB_DEVICE_ID_BTC_8193 0x0002
+
+#define USB_VENDOR_ID_FREESCALE 0x15A2
+#define USB_DEVICE_ID_FREESCALE_MX28 0x004F
+
+#define USB_VENDOR_ID_FRUCTEL 0x25B6
+#define USB_DEVICE_ID_GAMETEL_MT_MODE 0x0002
+
+#define USB_VENDOR_ID_GAMERON 0x0810
+#define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001
+#define USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR 0x0002
+
+#define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc
+#define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0003
+#define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS 0x0100
+
+#define USB_VENDOR_ID_GLAB 0x06c2
+#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038
+#define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039
+#define USB_DEVICE_ID_0_0_4_IF_KIT 0x0040
+#define USB_DEVICE_ID_0_16_16_IF_KIT 0x0044
+#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045
+#define USB_DEVICE_ID_0_8_7_IF_KIT 0x0051
+#define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053
+#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058
+
+#define USB_VENDOR_ID_GOODTOUCH 0x1aad
+#define USB_DEVICE_ID_GOODTOUCH_000f 0x000f
+
+#define USB_VENDOR_ID_GOTOP 0x08f2
+#define USB_DEVICE_ID_SUPER_Q2 0x007f
+#define USB_DEVICE_ID_GOGOPEN 0x00ce
+#define USB_DEVICE_ID_PENPOWER 0x00f4
+
+#define USB_VENDOR_ID_GREENASIA 0x0e8f
+#define USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD 0x3013
+
+#define USB_VENDOR_ID_GRETAGMACBETH 0x0971
+#define USB_DEVICE_ID_GRETAGMACBETH_HUEY 0x2005
+
+#define USB_VENDOR_ID_GRIFFIN 0x077d
+#define USB_DEVICE_ID_POWERMATE 0x0410
+#define USB_DEVICE_ID_SOUNDKNOB 0x04AA
+#define USB_DEVICE_ID_RADIOSHARK 0x627a
+
+#define USB_VENDOR_ID_GTCO 0x078c
+#define USB_DEVICE_ID_GTCO_90 0x0090
+#define USB_DEVICE_ID_GTCO_100 0x0100
+#define USB_DEVICE_ID_GTCO_101 0x0101
+#define USB_DEVICE_ID_GTCO_103 0x0103
+#define USB_DEVICE_ID_GTCO_104 0x0104
+#define USB_DEVICE_ID_GTCO_105 0x0105
+#define USB_DEVICE_ID_GTCO_106 0x0106
+#define USB_DEVICE_ID_GTCO_107 0x0107
+#define USB_DEVICE_ID_GTCO_108 0x0108
+#define USB_DEVICE_ID_GTCO_200 0x0200
+#define USB_DEVICE_ID_GTCO_201 0x0201
+#define USB_DEVICE_ID_GTCO_202 0x0202
+#define USB_DEVICE_ID_GTCO_203 0x0203
+#define USB_DEVICE_ID_GTCO_204 0x0204
+#define USB_DEVICE_ID_GTCO_205 0x0205
+#define USB_DEVICE_ID_GTCO_206 0x0206
+#define USB_DEVICE_ID_GTCO_207 0x0207
+#define USB_DEVICE_ID_GTCO_300 0x0300
+#define USB_DEVICE_ID_GTCO_301 0x0301
+#define USB_DEVICE_ID_GTCO_302 0x0302
+#define USB_DEVICE_ID_GTCO_303 0x0303
+#define USB_DEVICE_ID_GTCO_304 0x0304
+#define USB_DEVICE_ID_GTCO_305 0x0305
+#define USB_DEVICE_ID_GTCO_306 0x0306
+#define USB_DEVICE_ID_GTCO_307 0x0307
+#define USB_DEVICE_ID_GTCO_308 0x0308
+#define USB_DEVICE_ID_GTCO_309 0x0309
+#define USB_DEVICE_ID_GTCO_400 0x0400
+#define USB_DEVICE_ID_GTCO_401 0x0401
+#define USB_DEVICE_ID_GTCO_402 0x0402
+#define USB_DEVICE_ID_GTCO_403 0x0403
+#define USB_DEVICE_ID_GTCO_404 0x0404
+#define USB_DEVICE_ID_GTCO_405 0x0405
+#define USB_DEVICE_ID_GTCO_500 0x0500
+#define USB_DEVICE_ID_GTCO_501 0x0501
+#define USB_DEVICE_ID_GTCO_502 0x0502
+#define USB_DEVICE_ID_GTCO_503 0x0503
+#define USB_DEVICE_ID_GTCO_504 0x0504
+#define USB_DEVICE_ID_GTCO_1000 0x1000
+#define USB_DEVICE_ID_GTCO_1001 0x1001
+#define USB_DEVICE_ID_GTCO_1002 0x1002
+#define USB_DEVICE_ID_GTCO_1003 0x1003
+#define USB_DEVICE_ID_GTCO_1004 0x1004
+#define USB_DEVICE_ID_GTCO_1005 0x1005
+#define USB_DEVICE_ID_GTCO_1006 0x1006
+#define USB_DEVICE_ID_GTCO_1007 0x1007
+
+#define USB_VENDOR_ID_GYRATION 0x0c16
+#define USB_DEVICE_ID_GYRATION_REMOTE 0x0002
+#define USB_DEVICE_ID_GYRATION_REMOTE_2 0x0003
+#define USB_DEVICE_ID_GYRATION_REMOTE_3 0x0008
+
+#define USB_VENDOR_ID_HANWANG 0x0b57
+#define USB_DEVICE_ID_HANWANG_TABLET_FIRST 0x5000
+#define USB_DEVICE_ID_HANWANG_TABLET_LAST 0x8fff
+
+#define USB_VENDOR_ID_HANVON 0x20b3
+#define USB_DEVICE_ID_HANVON_MULTITOUCH 0x0a18
+
+#define USB_VENDOR_ID_HANVON_ALT 0x22ed
+#define USB_DEVICE_ID_HANVON_ALT_MULTITOUCH 0x1010
+
+#define USB_VENDOR_ID_HAPP 0x078b
+#define USB_DEVICE_ID_UGCI_DRIVING 0x0010
+#define USB_DEVICE_ID_UGCI_FLYING 0x0020
+#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030
+
+#define USB_VENDOR_ID_IDEACOM 0x1cb6
+#define USB_DEVICE_ID_IDEACOM_IDC6650 0x6650
+#define USB_DEVICE_ID_IDEACOM_IDC6651 0x6651
+
+#define USB_VENDOR_ID_ILITEK 0x222a
+#define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001
+
+#define USB_VENDOR_ID_ION 0x15e4
+#define USB_DEVICE_ID_ICADE 0x0132
+
+#define USB_VENDOR_ID_HOLTEK 0x1241
+#define USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP 0x5015
+
+#define USB_VENDOR_ID_HOLTEK_ALT 0x04d9
+#define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD 0xa055
+
+#define USB_VENDOR_ID_IMATION 0x0718
+#define USB_DEVICE_ID_DISC_STAKKA 0xd000
+
+#define USB_VENDOR_ID_INTEL_8086 0x8086
+#define USB_VENDOR_ID_INTEL_8087 0x8087
+#define USB_DEVICE_ID_SENSOR_HUB_1020 0x1020
+#define USB_DEVICE_ID_SENSOR_HUB_09FA 0x09FA
+
+#define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615
+#define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070
+
+#define USB_VENDOR_ID_JESS 0x0c45
+#define USB_DEVICE_ID_JESS_YUREX 0x1010
+
+#define USB_VENDOR_ID_KBGEAR 0x084e
+#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
+
+#define USB_VENDOR_ID_KENSINGTON 0x047d
+#define USB_DEVICE_ID_KS_SLIMBLADE 0x2041
+
+#define USB_VENDOR_ID_KWORLD 0x1b80
+#define USB_DEVICE_ID_KWORLD_RADIO_FM700 0xd700
+
+#define USB_VENDOR_ID_KEYTOUCH 0x0926
+#define USB_DEVICE_ID_KEYTOUCH_IEC 0x3333
+
+#define USB_VENDOR_ID_KYE 0x0458
+#define USB_DEVICE_ID_KYE_ERGO_525V 0x0087
+#define USB_DEVICE_ID_KYE_GPEN_560 0x5003
+#define USB_DEVICE_ID_KYE_EASYPEN_I405X 0x5010
+#define USB_DEVICE_ID_KYE_MOUSEPEN_I608X 0x5011
+#define USB_DEVICE_ID_KYE_EASYPEN_M610X 0x5013
+
+#define USB_VENDOR_ID_LABTEC 0x1020
+#define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006
+
+#define USB_VENDOR_ID_LCPOWER 0x1241
+#define USB_DEVICE_ID_LCPOWER_LC1000 0xf767
+
+#define USB_VENDOR_ID_LD 0x0f11
+#define USB_DEVICE_ID_LD_CASSY 0x1000
+#define USB_DEVICE_ID_LD_CASSY2 0x1001
+#define USB_DEVICE_ID_LD_POCKETCASSY 0x1010
+#define USB_DEVICE_ID_LD_POCKETCASSY2 0x1011
+#define USB_DEVICE_ID_LD_MOBILECASSY 0x1020
+#define USB_DEVICE_ID_LD_MOBILECASSY2 0x1021
+#define USB_DEVICE_ID_LD_MICROCASSYVOLTAGE 0x1031
+#define USB_DEVICE_ID_LD_MICROCASSYCURRENT 0x1032
+#define USB_DEVICE_ID_LD_MICROCASSYTIME 0x1033
+#define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE 0x1035
+#define USB_DEVICE_ID_LD_MICROCASSYPH 0x1038
+#define USB_DEVICE_ID_LD_JWM 0x1080
+#define USB_DEVICE_ID_LD_DMMP 0x1081
+#define USB_DEVICE_ID_LD_UMIP 0x1090
+#define USB_DEVICE_ID_LD_UMIC 0x10A0
+#define USB_DEVICE_ID_LD_UMIB 0x10B0
+#define USB_DEVICE_ID_LD_XRAY 0x1100
+#define USB_DEVICE_ID_LD_XRAY2 0x1101
+#define USB_DEVICE_ID_LD_XRAYCT 0x1110
+#define USB_DEVICE_ID_LD_VIDEOCOM 0x1200
+#define USB_DEVICE_ID_LD_MOTOR 0x1210
+#define USB_DEVICE_ID_LD_COM3LAB 0x2000
+#define USB_DEVICE_ID_LD_TELEPORT 0x2010
+#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020
+#define USB_DEVICE_ID_LD_POWERCONTROL 0x2030
+#define USB_DEVICE_ID_LD_MACHINETEST 0x2040
+#define USB_DEVICE_ID_LD_MOSTANALYSER 0x2050
+#define USB_DEVICE_ID_LD_MOSTANALYSER2 0x2051
+#define USB_DEVICE_ID_LD_ABSESP 0x2060
+#define USB_DEVICE_ID_LD_AUTODATABUS 0x2070
+#define USB_DEVICE_ID_LD_MCT 0x2080
+#define USB_DEVICE_ID_LD_HYBRID 0x2090
+#define USB_DEVICE_ID_LD_HEATCONTROL 0x20A0
+
+#define USB_VENDOR_ID_LENOVO 0x17ef
+#define USB_DEVICE_ID_LENOVO_TPKBD 0x6009
+
+#define USB_VENDOR_ID_LG 0x1fd2
+#define USB_DEVICE_ID_LG_MULTITOUCH 0x0064
+
+#define USB_VENDOR_ID_LOGITECH 0x046d
+#define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e
+#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
+#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110
+#define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
+#define USB_DEVICE_ID_LOGITECH_HARMONY_PS3 0x0306
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD 0xc20a
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD 0xc211
+#define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219
+#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283
+#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286
+#define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287
+#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294
+#define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293
+#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
+#define USB_DEVICE_ID_LOGITECH_DFP_WHEEL 0xc298
+#define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299
+#define USB_DEVICE_ID_LOGITECH_DFGT_WHEEL 0xc29a
+#define USB_DEVICE_ID_LOGITECH_G27_WHEEL 0xc29b
+#define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c
+#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a
+#define USB_DEVICE_ID_S510_RECEIVER 0xc50c
+#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
+#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512
+#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513
+#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER 0xc52b
+#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2 0xc532
+#define USB_DEVICE_ID_SPACETRAVELLER 0xc623
+#define USB_DEVICE_ID_SPACENAVIGATOR 0xc626
+#define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704
+#define USB_DEVICE_ID_DINOVO_EDGE 0xc714
+#define USB_DEVICE_ID_DINOVO_MINI 0xc71f
+#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2 0xca03
+
+#define USB_VENDOR_ID_LUMIO 0x202e
+#define USB_DEVICE_ID_CRYSTALTOUCH 0x0006
+#define USB_DEVICE_ID_CRYSTALTOUCH_DUAL 0x0007
+
+#define USB_VENDOR_ID_MADCATZ 0x0738
+#define USB_DEVICE_ID_MADCATZ_BEATPAD 0x4540
+
+#define USB_VENDOR_ID_MCC 0x09db
+#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076
+#define USB_DEVICE_ID_MCC_PMD1208LS 0x007a
+
+#define USB_VENDOR_ID_MGE 0x0463
+#define USB_DEVICE_ID_MGE_UPS 0xffff
+#define USB_DEVICE_ID_MGE_UPS1 0x0001
+
+#define USB_VENDOR_ID_MICROCHIP 0x04d8
+#define USB_DEVICE_ID_PICKIT1 0x0032
+#define USB_DEVICE_ID_PICKIT2 0x0033
+#define USB_DEVICE_ID_PICOLCD 0xc002
+#define USB_DEVICE_ID_PICOLCD_BOOTLOADER 0xf002
+
+#define USB_VENDOR_ID_MICROSOFT 0x045e
+#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
+#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
+#define USB_DEVICE_ID_MS_NE4K 0x00db
+#define USB_DEVICE_ID_MS_LK6K 0x00f9
+#define USB_DEVICE_ID_MS_PRESENTER_8K_BT 0x0701
+#define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713
+#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K 0x0730
+#define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c
+
+#define USB_VENDOR_ID_MOJO 0x8282
+#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
+
+#define USB_VENDOR_ID_MONTEREY 0x0566
+#define USB_DEVICE_ID_GENIUS_KB29E 0x3004
+
+#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
+#define USB_DEVICE_ID_N_S_HARMONY 0xc359
+
+#define USB_VENDOR_ID_NATSU 0x08b7
+#define USB_DEVICE_ID_NATSU_GAMEPAD 0x0001
+
+#define USB_VENDOR_ID_NCR 0x0404
+#define USB_DEVICE_ID_NCR_FIRST 0x0300
+#define USB_DEVICE_ID_NCR_LAST 0x03ff
+
+#define USB_VENDOR_ID_NEC 0x073e
+#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
+
+#define USB_VENDOR_ID_NEXTWINDOW 0x1926
+#define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003
+
+#define USB_VENDOR_ID_NINTENDO 0x057e
+#define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306
+
+#define USB_VENDOR_ID_NOVATEK 0x0603
+#define USB_DEVICE_ID_NOVATEK_PCT 0x0600
+
+#define USB_VENDOR_ID_NTRIG 0x1b96
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1 0x0003
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2 0x0004
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_3 0x0005
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_4 0x0006
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_5 0x0007
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_6 0x0008
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_7 0x0009
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_8 0x000A
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_9 0x000B
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_10 0x000C
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_11 0x000D
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_12 0x000E
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_13 0x000F
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_14 0x0010
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_15 0x0011
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_16 0x0012
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_17 0x0013
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18 0x0014
+
+#define USB_VENDOR_ID_ONTRAK 0x0a07
+#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
+
+#define USB_VENDOR_ID_ORTEK 0x05a4
+#define USB_DEVICE_ID_ORTEK_PKB1700 0x1700
+#define USB_DEVICE_ID_ORTEK_WKB2000 0x2000
+
+#define USB_VENDOR_ID_PANASONIC 0x04da
+#define USB_DEVICE_ID_PANABOARD_UBT780 0x1044
+#define USB_DEVICE_ID_PANABOARD_UBT880 0x104d
+
+#define USB_VENDOR_ID_PANJIT 0x134c
+
+#define USB_VENDOR_ID_PANTHERLORD 0x0810
+#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001
+
+#define USB_VENDOR_ID_PENMOUNT 0x14e1
+#define USB_DEVICE_ID_PENMOUNT_PCI 0x3500
+
+#define USB_VENDOR_ID_PETALYNX 0x18b1
+#define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037
+
+#define USB_VENDOR_ID_PHILIPS 0x0471
+#define USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE 0x0617
+
+#define USB_VENDOR_ID_PI_ENGINEERING 0x05f3
+#define USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL 0xff
+
+#define USB_VENDOR_ID_PIXART 0x093a
+#define USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN 0x8001
+#define USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1 0x8002
+#define USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2 0x8003
+
+#define USB_VENDOR_ID_PLAYDOTCOM 0x0b43
+#define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII 0x0003
+
+#define USB_VENDOR_ID_POWERCOM 0x0d9f
+#define USB_DEVICE_ID_POWERCOM_UPS 0x0002
+
+#define USB_VENDOR_ID_PRODIGE 0x05af
+#define USB_DEVICE_ID_PRODIGE_CORDLESS 0x3062
+
+#define USB_VENDOR_ID_QUANTA 0x0408
+#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000
+#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001 0x3001
+#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008 0x3008
+
+#define USB_VENDOR_ID_ROCCAT 0x1e7d
+#define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4
+#define USB_DEVICE_ID_ROCCAT_ISKU 0x319c
+#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
+#define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51
+#define USB_DEVICE_ID_ROCCAT_KONEXTD 0x2e22
+#define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50
+#define USB_DEVICE_ID_ROCCAT_LUA 0x2c2e
+#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24
+#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6
+#define USB_DEVICE_ID_ROCCAT_SAVU 0x2d5a
+
+#define USB_VENDOR_ID_SAITEK 0x06a3
+#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
+#define USB_DEVICE_ID_SAITEK_PS1000 0x0621
+
+#define USB_VENDOR_ID_SAMSUNG 0x0419
+#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
+#define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600
+
+#define USB_VENDOR_ID_SENNHEISER 0x1395
+#define USB_DEVICE_ID_SENNHEISER_BTD500USB 0x002c
+
+#define USB_VENDOR_ID_SIGMA_MICRO 0x1c4f
+#define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD 0x0002
+
+#define USB_VENDOR_ID_SIGMATEL 0x066F
+#define USB_DEVICE_ID_SIGMATEL_STMP3780 0x3780
+
+#define USB_VENDOR_ID_SKYCABLE 0x1223
+#define USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER 0x3F07
+
+#define USB_VENDOR_ID_SONY 0x054c
+#define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b
+#define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306
+#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
+#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f
+
+#define USB_VENDOR_ID_SOUNDGRAPH 0x15c2
+#define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034
+#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST 0x0046
+
+#define USB_VENDOR_ID_STANTUM 0x1f87
+#define USB_DEVICE_ID_MTP 0x0002
+
+#define USB_VENDOR_ID_STANTUM_STM 0x0483
+#define USB_DEVICE_ID_MTP_STM 0x3261
+#define USB_DEVICE_ID_SENSOR_HUB_7014 0x7014
+
+#define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403
+#define USB_DEVICE_ID_MTP_SITRONIX 0x5001
+
+#define USB_VENDOR_ID_SUN 0x0430
+#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
+
+#define USB_VENDOR_ID_SUNPLUS 0x04fc
+#define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
+
+#define USB_VENDOR_ID_SYMBOL 0x05e0
+#define USB_DEVICE_ID_SYMBOL_SCANNER_1 0x0800
+#define USB_DEVICE_ID_SYMBOL_SCANNER_2 0x1300
+
+#define USB_VENDOR_ID_SYNAPTICS 0x06cb
+#define USB_DEVICE_ID_SYNAPTICS_TP 0x0001
+#define USB_DEVICE_ID_SYNAPTICS_INT_TP 0x0002
+#define USB_DEVICE_ID_SYNAPTICS_CPAD 0x0003
+#define USB_DEVICE_ID_SYNAPTICS_TS 0x0006
+#define USB_DEVICE_ID_SYNAPTICS_STICK 0x0007
+#define USB_DEVICE_ID_SYNAPTICS_WP 0x0008
+#define USB_DEVICE_ID_SYNAPTICS_COMP_TP 0x0009
+#define USB_DEVICE_ID_SYNAPTICS_WTP 0x0010
+#define USB_DEVICE_ID_SYNAPTICS_DPAD 0x0013
+
+#define USB_VENDOR_ID_THRUSTMASTER 0x044f
+
+#define USB_VENDOR_ID_TIVO 0x150a
+#define USB_DEVICE_ID_TIVO_SLIDE_BT 0x1200
+#define USB_DEVICE_ID_TIVO_SLIDE 0x1201
+
+#define USB_VENDOR_ID_TOPSEED 0x0766
+#define USB_DEVICE_ID_TOPSEED_CYBERLINK 0x0204
+
+#define USB_VENDOR_ID_TOPSEED2 0x1784
+#define USB_DEVICE_ID_TOPSEED2_RF_COMBO 0x0004
+#define USB_DEVICE_ID_TOPSEED2_PERIPAD_701 0x0016
+
+#define USB_VENDOR_ID_TOPMAX 0x0663
+#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103
+
+#define USB_VENDOR_ID_TOUCH_INTL 0x1e5e
+#define USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH 0x0313
+
+#define USB_VENDOR_ID_TOUCHPACK 0x1bfd
+#define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688
+
+#define USB_VENDOR_ID_TPV 0x25aa
+#define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN 0x8883
+
+#define USB_VENDOR_ID_TURBOX 0x062a
+#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201
+#define USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART 0x7100
+
+#define USB_VENDOR_ID_TWINHAN 0x6253
+#define USB_DEVICE_ID_TWINHAN_IR_REMOTE 0x0100
+
+#define USB_VENDOR_ID_UCLOGIC 0x5543
+#define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042
+#define USB_DEVICE_ID_UCLOGIC_TABLET_KNA5 0x6001
+#define USB_DEVICE_ID_UCLOGIC_TABLET_TWA60 0x0064
+#define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U 0x0003
+#define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004
+#define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005
+#define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 0x0064
+#define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 0x0522
+#define USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60 0x0781
+
+#define USB_VENDOR_ID_UNITEC 0x227d
+#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709
+#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19 0x0a19
+
+#define USB_VENDOR_ID_VERNIER 0x08f7
+#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001
+#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002
+#define USB_DEVICE_ID_VERNIER_SKIP 0x0003
+#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004
+#define USB_DEVICE_ID_VERNIER_LCSPEC 0x0006
+
+#define USB_VENDOR_ID_WACOM 0x056a
+#define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81
+#define USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH 0x00BD
+
+#define USB_VENDOR_ID_WALTOP 0x172f
+#define USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH 0x0032
+#define USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH 0x0034
+#define USB_DEVICE_ID_WALTOP_Q_PAD 0x0037
+#define USB_DEVICE_ID_WALTOP_PID_0038 0x0038
+#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH 0x0501
+#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH 0x0500
+#define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET 0x0502
+
+#define USB_VENDOR_ID_WISEGROUP 0x0925
+#define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005
+#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
+#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104
+#define USB_DEVICE_ID_8_8_4_IF_KIT 0x8201
+#define USB_DEVICE_ID_SUPER_JOY_BOX_3 0x8888
+#define USB_DEVICE_ID_QUAD_USB_JOYPAD 0x8800
+#define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866
+
+#define USB_VENDOR_ID_WISEGROUP_LTD 0x6666
+#define USB_VENDOR_ID_WISEGROUP_LTD2 0x6677
+#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
+#define USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO 0x8801
+#define USB_DEVICE_ID_SUPER_DUAL_BOX_PRO 0x8802
+#define USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO 0x8804
+
+#define USB_VENDOR_ID_X_TENSIONS 0x1ae7
+#define USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE 0x9001
+
+#define USB_VENDOR_ID_XAT 0x2505
+#define USB_DEVICE_ID_XAT_CSR 0x0220
+
+#define USB_VENDOR_ID_XIROKU 0x1477
+#define USB_DEVICE_ID_XIROKU_SPX 0x1006
+#define USB_DEVICE_ID_XIROKU_MPX 0x1007
+#define USB_DEVICE_ID_XIROKU_CSR 0x100e
+#define USB_DEVICE_ID_XIROKU_SPX1 0x1021
+#define USB_DEVICE_ID_XIROKU_CSR1 0x1022
+#define USB_DEVICE_ID_XIROKU_MPX1 0x1023
+#define USB_DEVICE_ID_XIROKU_SPX2 0x1024
+#define USB_DEVICE_ID_XIROKU_CSR2 0x1025
+#define USB_DEVICE_ID_XIROKU_MPX2 0x1026
+
+#define USB_VENDOR_ID_YEALINK 0x6993
+#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001
+
+#define USB_VENDOR_ID_ZEROPLUS 0x0c12
+
+#define USB_VENDOR_ID_ZYDACRON 0x13EC
+#define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL 0x0006
+
+#define USB_VENDOR_ID_ZYTRONIC 0x14c8
+#define USB_DEVICE_ID_ZYTRONIC_ZXY100 0x0005
+
+#define USB_VENDOR_ID_PRIMAX 0x0461
+#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
+
+#endif
diff --git a/backport/compat/kfifo.c b/backport/compat/kfifo.c
new file mode 100644
index 00000000..96e1bdfd
--- /dev/null
+++ b/backport/compat/kfifo.c
@@ -0,0 +1,608 @@
+/*
+ * A generic kernel FIFO implementation
+ *
+ * Copyright (C) 2009/2010 Stefani Seibold <stefani@seibold.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/log2.h>
+#include <linux/uaccess.h>
+#include <linux/kfifo.h>
+
+/*
+ * internal helper to calculate the unused elements in a fifo
+ */
+static inline unsigned int kfifo_unused(struct __kfifo *fifo)
+{
+ return (fifo->mask + 1) - (fifo->in - fifo->out);
+}
+
+int __kfifo_alloc(struct __kfifo *fifo, unsigned int size,
+ size_t esize, gfp_t gfp_mask)
+{
+ /*
+ * round down to the next power of 2, since our 'let the indices
+ * wrap' technique works only in this case.
+ */
+ if (!is_power_of_2(size))
+ size = rounddown_pow_of_two(size);
+
+ fifo->in = 0;
+ fifo->out = 0;
+ fifo->esize = esize;
+
+ if (size < 2) {
+ fifo->data = NULL;
+ fifo->mask = 0;
+ return -EINVAL;
+ }
+
+ fifo->data = kmalloc(size * esize, gfp_mask);
+
+ if (!fifo->data) {
+ fifo->mask = 0;
+ return -ENOMEM;
+ }
+ fifo->mask = size - 1;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__kfifo_alloc);
+
+void __kfifo_free(struct __kfifo *fifo)
+{
+ kfree(fifo->data);
+ fifo->in = 0;
+ fifo->out = 0;
+ fifo->esize = 0;
+ fifo->data = NULL;
+ fifo->mask = 0;
+}
+EXPORT_SYMBOL_GPL(__kfifo_free);
+
+int __kfifo_init(struct __kfifo *fifo, void *buffer,
+ unsigned int size, size_t esize)
+{
+ size /= esize;
+
+ if (!is_power_of_2(size))
+ size = rounddown_pow_of_two(size);
+
+ fifo->in = 0;
+ fifo->out = 0;
+ fifo->esize = esize;
+ fifo->data = buffer;
+
+ if (size < 2) {
+ fifo->mask = 0;
+ return -EINVAL;
+ }
+ fifo->mask = size - 1;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__kfifo_init);
+
+static void kfifo_copy_in(struct __kfifo *fifo, const void *src,
+ unsigned int len, unsigned int off)
+{
+ unsigned int size = fifo->mask + 1;
+ unsigned int esize = fifo->esize;
+ unsigned int l;
+
+ off &= fifo->mask;
+ if (esize != 1) {
+ off *= esize;
+ size *= esize;
+ len *= esize;
+ }
+ l = min(len, size - off);
+
+ memcpy(fifo->data + off, src, l);
+ memcpy(fifo->data, src + l, len - l);
+ /*
+ * make sure that the data in the fifo is up to date before
+ * incrementing the fifo->in index counter
+ */
+ smp_wmb();
+}
+
+unsigned int __kfifo_in(struct __kfifo *fifo,
+ const void *buf, unsigned int len)
+{
+ unsigned int l;
+
+ l = kfifo_unused(fifo);
+ if (len > l)
+ len = l;
+
+ kfifo_copy_in(fifo, buf, len, fifo->in);
+ fifo->in += len;
+ return len;
+}
+EXPORT_SYMBOL_GPL(__kfifo_in);
+
+static void kfifo_copy_out(struct __kfifo *fifo, void *dst,
+ unsigned int len, unsigned int off)
+{
+ unsigned int size = fifo->mask + 1;
+ unsigned int esize = fifo->esize;
+ unsigned int l;
+
+ off &= fifo->mask;
+ if (esize != 1) {
+ off *= esize;
+ size *= esize;
+ len *= esize;
+ }
+ l = min(len, size - off);
+
+ memcpy(dst, fifo->data + off, l);
+ memcpy(dst + l, fifo->data, len - l);
+ /*
+ * make sure that the data is copied before
+ * incrementing the fifo->out index counter
+ */
+ smp_wmb();
+}
+
+unsigned int __kfifo_out_peek(struct __kfifo *fifo,
+ void *buf, unsigned int len)
+{
+ unsigned int l;
+
+ l = fifo->in - fifo->out;
+ if (len > l)
+ len = l;
+
+ kfifo_copy_out(fifo, buf, len, fifo->out);
+ return len;
+}
+EXPORT_SYMBOL_GPL(__kfifo_out_peek);
+
+unsigned int __kfifo_out(struct __kfifo *fifo,
+ void *buf, unsigned int len)
+{
+ len = __kfifo_out_peek(fifo, buf, len);
+ fifo->out += len;
+ return len;
+}
+EXPORT_SYMBOL_GPL(__kfifo_out);
+
+static unsigned long kfifo_copy_from_user(struct __kfifo *fifo,
+ const void __user *from, unsigned int len, unsigned int off,
+ unsigned int *copied)
+{
+ unsigned int size = fifo->mask + 1;
+ unsigned int esize = fifo->esize;
+ unsigned int l;
+ unsigned long ret;
+
+ off &= fifo->mask;
+ if (esize != 1) {
+ off *= esize;
+ size *= esize;
+ len *= esize;
+ }
+ l = min(len, size - off);
+
+ ret = copy_from_user(fifo->data + off, from, l);
+ if (unlikely(ret))
+ ret = DIV_ROUND_UP(ret + len - l, esize);
+ else {
+ ret = copy_from_user(fifo->data, from + l, len - l);
+ if (unlikely(ret))
+ ret = DIV_ROUND_UP(ret, esize);
+ }
+ /*
+ * make sure that the data in the fifo is up to date before
+ * incrementing the fifo->in index counter
+ */
+ smp_wmb();
+ *copied = len - ret;
+ /* return the number of elements which are not copied */
+ return ret;
+}
+
+int __kfifo_from_user(struct __kfifo *fifo, const void __user *from,
+ unsigned long len, unsigned int *copied)
+{
+ unsigned int l;
+ unsigned long ret;
+ unsigned int esize = fifo->esize;
+ int err;
+
+ if (esize != 1)
+ len /= esize;
+
+ l = kfifo_unused(fifo);
+ if (len > l)
+ len = l;
+
+ ret = kfifo_copy_from_user(fifo, from, len, fifo->in, copied);
+ if (unlikely(ret)) {
+ len -= ret;
+ err = -EFAULT;
+ } else
+ err = 0;
+ fifo->in += len;
+ return err;
+}
+EXPORT_SYMBOL_GPL(__kfifo_from_user);
+
+static unsigned long kfifo_copy_to_user(struct __kfifo *fifo, void __user *to,
+ unsigned int len, unsigned int off, unsigned int *copied)
+{
+ unsigned int l;
+ unsigned long ret;
+ unsigned int size = fifo->mask + 1;
+ unsigned int esize = fifo->esize;
+
+ off &= fifo->mask;
+ if (esize != 1) {
+ off *= esize;
+ size *= esize;
+ len *= esize;
+ }
+ l = min(len, size - off);
+
+ ret = copy_to_user(to, fifo->data + off, l);
+ if (unlikely(ret))
+ ret = DIV_ROUND_UP(ret + len - l, esize);
+ else {
+ ret = copy_to_user(to + l, fifo->data, len - l);
+ if (unlikely(ret))
+ ret = DIV_ROUND_UP(ret, esize);
+ }
+ /*
+ * make sure that the data is copied before
+ * incrementing the fifo->out index counter
+ */
+ smp_wmb();
+ *copied = len - ret;
+ /* return the number of elements which are not copied */
+ return ret;
+}
+
+int __kfifo_to_user(struct __kfifo *fifo, void __user *to,
+ unsigned long len, unsigned int *copied)
+{
+ unsigned int l;
+ unsigned long ret;
+ unsigned int esize = fifo->esize;
+ int err;
+
+ if (esize != 1)
+ len /= esize;
+
+ l = fifo->in - fifo->out;
+ if (len > l)
+ len = l;
+ ret = kfifo_copy_to_user(fifo, to, len, fifo->out, copied);
+ if (unlikely(ret)) {
+ len -= ret;
+ err = -EFAULT;
+ } else
+ err = 0;
+ fifo->out += len;
+ return err;
+}
+EXPORT_SYMBOL_GPL(__kfifo_to_user);
+
+static int setup_sgl_buf(struct scatterlist *sgl, void *buf,
+ int nents, unsigned int len)
+{
+ int n;
+ unsigned int l;
+ unsigned int off;
+ struct page *page;
+
+ if (!nents)
+ return 0;
+
+ if (!len)
+ return 0;
+
+ n = 0;
+ page = virt_to_page(buf);
+ off = offset_in_page(buf);
+ l = 0;
+
+ while (len >= l + PAGE_SIZE - off) {
+ struct page *npage;
+
+ l += PAGE_SIZE;
+ buf += PAGE_SIZE;
+ npage = virt_to_page(buf);
+ if (page_to_phys(page) != page_to_phys(npage) - l) {
+ sg_set_page(sgl, page, l - off, off);
+ sgl = sg_next(sgl);
+ if (++n == nents || sgl == NULL)
+ return n;
+ page = npage;
+ len -= l - off;
+ l = off = 0;
+ }
+ }
+ sg_set_page(sgl, page, len, off);
+ return n + 1;
+}
+
+static unsigned int setup_sgl(struct __kfifo *fifo, struct scatterlist *sgl,
+ int nents, unsigned int len, unsigned int off)
+{
+ unsigned int size = fifo->mask + 1;
+ unsigned int esize = fifo->esize;
+ unsigned int l;
+ unsigned int n;
+
+ off &= fifo->mask;
+ if (esize != 1) {
+ off *= esize;
+ size *= esize;
+ len *= esize;
+ }
+ l = min(len, size - off);
+
+ n = setup_sgl_buf(sgl, fifo->data + off, nents, l);
+ n += setup_sgl_buf(sgl + n, fifo->data, nents - n, len - l);
+
+ return n;
+}
+
+unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo,
+ struct scatterlist *sgl, int nents, unsigned int len)
+{
+ unsigned int l;
+
+ l = kfifo_unused(fifo);
+ if (len > l)
+ len = l;
+
+ return setup_sgl(fifo, sgl, nents, len, fifo->in);
+}
+EXPORT_SYMBOL_GPL(__kfifo_dma_in_prepare);
+
+unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo,
+ struct scatterlist *sgl, int nents, unsigned int len)
+{
+ unsigned int l;
+
+ l = fifo->in - fifo->out;
+ if (len > l)
+ len = l;
+
+ return setup_sgl(fifo, sgl, nents, len, fifo->out);
+}
+EXPORT_SYMBOL_GPL(__kfifo_dma_out_prepare);
+
+unsigned int __kfifo_max_r(unsigned int len, size_t recsize)
+{
+ unsigned int max = (1 << (recsize << 3)) - 1;
+
+ if (len > max)
+ return max;
+ return len;
+}
+
+#define __KFIFO_PEEK(data, out, mask) \
+ ((data)[(out) & (mask)])
+/*
+ * __kfifo_peek_n internal helper function for determinate the length of
+ * the next record in the fifo
+ */
+static unsigned int __kfifo_peek_n(struct __kfifo *fifo, size_t recsize)
+{
+ unsigned int l;
+ unsigned int mask = fifo->mask;
+ unsigned char *data = fifo->data;
+
+ l = __KFIFO_PEEK(data, fifo->out, mask);
+
+ if (--recsize)
+ l |= __KFIFO_PEEK(data, fifo->out + 1, mask) << 8;
+
+ return l;
+}
+
+#define __KFIFO_POKE(data, in, mask, val) \
+ ( \
+ (data)[(in) & (mask)] = (unsigned char)(val) \
+ )
+
+/*
+ * __kfifo_poke_n internal helper function for storeing the length of
+ * the record into the fifo
+ */
+static void __kfifo_poke_n(struct __kfifo *fifo, unsigned int n, size_t recsize)
+{
+ unsigned int mask = fifo->mask;
+ unsigned char *data = fifo->data;
+
+ __KFIFO_POKE(data, fifo->in, mask, n);
+
+ if (recsize > 1)
+ __KFIFO_POKE(data, fifo->in + 1, mask, n >> 8);
+}
+
+unsigned int __kfifo_len_r(struct __kfifo *fifo, size_t recsize)
+{
+ return __kfifo_peek_n(fifo, recsize);
+}
+EXPORT_SYMBOL_GPL(__kfifo_len_r);
+
+unsigned int __kfifo_in_r(struct __kfifo *fifo, const void *buf,
+ unsigned int len, size_t recsize)
+{
+ if (len + recsize > kfifo_unused(fifo))
+ return 0;
+
+ __kfifo_poke_n(fifo, len, recsize);
+
+ kfifo_copy_in(fifo, buf, len, fifo->in + recsize);
+ fifo->in += len + recsize;
+ return len;
+}
+EXPORT_SYMBOL_GPL(__kfifo_in_r);
+
+static unsigned int kfifo_out_copy_r(struct __kfifo *fifo,
+ void *buf, unsigned int len, size_t recsize, unsigned int *n)
+{
+ *n = __kfifo_peek_n(fifo, recsize);
+
+ if (len > *n)
+ len = *n;
+
+ kfifo_copy_out(fifo, buf, len, fifo->out + recsize);
+ return len;
+}
+
+unsigned int __kfifo_out_peek_r(struct __kfifo *fifo, void *buf,
+ unsigned int len, size_t recsize)
+{
+ unsigned int n;
+
+ if (fifo->in == fifo->out)
+ return 0;
+
+ return kfifo_out_copy_r(fifo, buf, len, recsize, &n);
+}
+EXPORT_SYMBOL_GPL(__kfifo_out_peek_r);
+
+unsigned int __kfifo_out_r(struct __kfifo *fifo, void *buf,
+ unsigned int len, size_t recsize)
+{
+ unsigned int n;
+
+ if (fifo->in == fifo->out)
+ return 0;
+
+ len = kfifo_out_copy_r(fifo, buf, len, recsize, &n);
+ fifo->out += n + recsize;
+ return len;
+}
+EXPORT_SYMBOL_GPL(__kfifo_out_r);
+
+void __kfifo_skip_r(struct __kfifo *fifo, size_t recsize)
+{
+ unsigned int n;
+
+ n = __kfifo_peek_n(fifo, recsize);
+ fifo->out += n + recsize;
+}
+EXPORT_SYMBOL_GPL(__kfifo_skip_r);
+
+int __kfifo_from_user_r(struct __kfifo *fifo, const void __user *from,
+ unsigned long len, unsigned int *copied, size_t recsize)
+{
+ unsigned long ret;
+
+ len = __kfifo_max_r(len, recsize);
+
+ if (len + recsize > kfifo_unused(fifo)) {
+ *copied = 0;
+ return 0;
+ }
+
+ __kfifo_poke_n(fifo, len, recsize);
+
+ ret = kfifo_copy_from_user(fifo, from, len, fifo->in + recsize, copied);
+ if (unlikely(ret)) {
+ *copied = 0;
+ return -EFAULT;
+ }
+ fifo->in += len + recsize;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__kfifo_from_user_r);
+
+int __kfifo_to_user_r(struct __kfifo *fifo, void __user *to,
+ unsigned long len, unsigned int *copied, size_t recsize)
+{
+ unsigned long ret;
+ unsigned int n;
+
+ if (fifo->in == fifo->out) {
+ *copied = 0;
+ return 0;
+ }
+
+ n = __kfifo_peek_n(fifo, recsize);
+ if (len > n)
+ len = n;
+
+ ret = kfifo_copy_to_user(fifo, to, len, fifo->out + recsize, copied);
+ if (unlikely(ret)) {
+ *copied = 0;
+ return -EFAULT;
+ }
+ fifo->out += n + recsize;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__kfifo_to_user_r);
+
+unsigned int __kfifo_dma_in_prepare_r(struct __kfifo *fifo,
+ struct scatterlist *sgl, int nents, unsigned int len, size_t recsize)
+{
+ if (!nents)
+ BUG();
+
+ len = __kfifo_max_r(len, recsize);
+
+ if (len + recsize > kfifo_unused(fifo))
+ return 0;
+
+ return setup_sgl(fifo, sgl, nents, len, fifo->in + recsize);
+}
+EXPORT_SYMBOL_GPL(__kfifo_dma_in_prepare_r);
+
+void __kfifo_dma_in_finish_r(struct __kfifo *fifo,
+ unsigned int len, size_t recsize)
+{
+ len = __kfifo_max_r(len, recsize);
+ __kfifo_poke_n(fifo, len, recsize);
+ fifo->in += len + recsize;
+}
+EXPORT_SYMBOL_GPL(__kfifo_dma_in_finish_r);
+
+unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo,
+ struct scatterlist *sgl, int nents, unsigned int len, size_t recsize)
+{
+ if (!nents)
+ BUG();
+
+ len = __kfifo_max_r(len, recsize);
+
+ if (len + recsize > fifo->in - fifo->out)
+ return 0;
+
+ return setup_sgl(fifo, sgl, nents, len, fifo->out + recsize);
+}
+EXPORT_SYMBOL_GPL(__kfifo_dma_out_prepare_r);
+
+void __kfifo_dma_out_finish_r(struct __kfifo *fifo, size_t recsize)
+{
+ unsigned int len;
+
+ len = __kfifo_peek_n(fifo, recsize);
+ fifo->out += len + recsize;
+}
+EXPORT_SYMBOL_GPL(__kfifo_dma_out_finish_r);
diff --git a/backport/compat/kstrtox.c b/backport/compat/kstrtox.c
new file mode 100644
index 00000000..fdbc56eb
--- /dev/null
+++ b/backport/compat/kstrtox.c
@@ -0,0 +1,236 @@
+/*
+ * Convert integer string representation to an integer.
+ * If an integer doesn't fit into specified type, -E is returned.
+ *
+ * Integer starts with optional sign.
+ * kstrtou*() functions do not accept sign "-".
+ *
+ * Radix 0 means autodetection: leading "0x" implies radix 16,
+ * leading "0" implies radix 8, otherwise radix is 10.
+ * Autodetection hints work after optional sign, but not before.
+ *
+ * If -E is returned, result is not touched.
+ */
+#include <linux/kernel.h>
+/*
+ * kstrto* was included in kernel 2.6.38.4 and causes conflicts with the
+ * version included in compat-drivers. We use strict_strtol to check if
+ * kstrto* is already available.
+ */
+#ifndef strict_strtoll
+
+#include <linux/ctype.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+static inline char _tolower(const char c)
+{
+ return c | 0x20;
+}
+
+static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
+{
+ unsigned long long acc;
+ int ok;
+
+ if (base == 0) {
+ if (s[0] == '0') {
+ if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
+ base = 16;
+ else
+ base = 8;
+ } else
+ base = 10;
+ }
+ if (base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
+ s += 2;
+
+ acc = 0;
+ ok = 0;
+ while (*s) {
+ unsigned int val;
+
+ if ('0' <= *s && *s <= '9')
+ val = *s - '0';
+ else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f')
+ val = _tolower(*s) - 'a' + 10;
+ else if (*s == '\n') {
+ if (*(s + 1) == '\0')
+ break;
+ else
+ return -EINVAL;
+ } else
+ return -EINVAL;
+
+ if (val >= base)
+ return -EINVAL;
+ if (acc > div_u64(ULLONG_MAX - val, base))
+ return -ERANGE;
+ acc = acc * base + val;
+ ok = 1;
+
+ s++;
+ }
+ if (!ok)
+ return -EINVAL;
+ *res = acc;
+ return 0;
+}
+
+int kstrtoull(const char *s, unsigned int base, unsigned long long *res)
+{
+ if (s[0] == '+')
+ s++;
+ return _kstrtoull(s, base, res);
+}
+EXPORT_SYMBOL_GPL(kstrtoull);
+
+int kstrtoll(const char *s, unsigned int base, long long *res)
+{
+ unsigned long long tmp;
+ int rv;
+
+ if (s[0] == '-') {
+ rv = _kstrtoull(s + 1, base, &tmp);
+ if (rv < 0)
+ return rv;
+ if ((long long)(-tmp) >= 0)
+ return -ERANGE;
+ *res = -tmp;
+ } else {
+ rv = kstrtoull(s, base, &tmp);
+ if (rv < 0)
+ return rv;
+ if ((long long)tmp < 0)
+ return -ERANGE;
+ *res = tmp;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kstrtoll);
+
+/* Internal, do not use. */
+int _kstrtoul(const char *s, unsigned int base, unsigned long *res)
+{
+ unsigned long long tmp;
+ int rv;
+
+ rv = kstrtoull(s, base, &tmp);
+ if (rv < 0)
+ return rv;
+ if (tmp != (unsigned long long)(unsigned long)tmp)
+ return -ERANGE;
+ *res = tmp;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(_kstrtoul);
+
+/* Internal, do not use. */
+int _kstrtol(const char *s, unsigned int base, long *res)
+{
+ long long tmp;
+ int rv;
+
+ rv = kstrtoll(s, base, &tmp);
+ if (rv < 0)
+ return rv;
+ if (tmp != (long long)(long)tmp)
+ return -ERANGE;
+ *res = tmp;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(_kstrtol);
+
+int kstrtouint(const char *s, unsigned int base, unsigned int *res)
+{
+ unsigned long long tmp;
+ int rv;
+
+ rv = kstrtoull(s, base, &tmp);
+ if (rv < 0)
+ return rv;
+ if (tmp != (unsigned long long)(unsigned int)tmp)
+ return -ERANGE;
+ *res = tmp;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kstrtouint);
+
+int kstrtoint(const char *s, unsigned int base, int *res)
+{
+ long long tmp;
+ int rv;
+
+ rv = kstrtoll(s, base, &tmp);
+ if (rv < 0)
+ return rv;
+ if (tmp != (long long)(int)tmp)
+ return -ERANGE;
+ *res = tmp;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kstrtoint);
+
+int kstrtou16(const char *s, unsigned int base, u16 *res)
+{
+ unsigned long long tmp;
+ int rv;
+
+ rv = kstrtoull(s, base, &tmp);
+ if (rv < 0)
+ return rv;
+ if (tmp != (unsigned long long)(u16)tmp)
+ return -ERANGE;
+ *res = tmp;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kstrtou16);
+
+int kstrtos16(const char *s, unsigned int base, s16 *res)
+{
+ long long tmp;
+ int rv;
+
+ rv = kstrtoll(s, base, &tmp);
+ if (rv < 0)
+ return rv;
+ if (tmp != (long long)(s16)tmp)
+ return -ERANGE;
+ *res = tmp;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kstrtos16);
+
+int kstrtou8(const char *s, unsigned int base, u8 *res)
+{
+ unsigned long long tmp;
+ int rv;
+
+ rv = kstrtoull(s, base, &tmp);
+ if (rv < 0)
+ return rv;
+ if (tmp != (unsigned long long)(u8)tmp)
+ return -ERANGE;
+ *res = tmp;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kstrtou8);
+
+int kstrtos8(const char *s, unsigned int base, s8 *res)
+{
+ long long tmp;
+ int rv;
+
+ rv = kstrtoll(s, base, &tmp);
+ if (rv < 0)
+ return rv;
+ if (tmp != (long long)(s8)tmp)
+ return -ERANGE;
+ *res = tmp;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kstrtos8);
+#endif /* #ifndef strict_strtol */
diff --git a/backport/compat/main.c b/backport/compat/main.c
new file mode 100644
index 00000000..6f1bfb75
--- /dev/null
+++ b/backport/compat/main.c
@@ -0,0 +1,63 @@
+#include <linux/module.h>
+#include "compat-2.6.34.h"
+
+MODULE_AUTHOR("Luis R. Rodriguez");
+MODULE_DESCRIPTION("Kernel backport module");
+MODULE_LICENSE("GPL");
+
+#ifndef BACKPORTED_KERNEL_NAME
+#error "You need a BACKPORTED_KERNEL_NAME"
+#endif
+
+#ifndef BACKPORTED_KERNEL_VERSION
+#error "You need a BACKPORTED_KERNEL_VERSION"
+#endif
+
+#ifndef BACKPORTS_VERSION
+#error "You need a BACKPORTS_VERSION"
+#endif
+
+static char *backported_kernel_name = BACKPORTED_KERNEL_NAME;
+static char *backported_kernel_version = BACKPORTED_KERNEL_VERSION;
+static char *backports_version = BACKPORTS_VERSION;
+
+module_param(backported_kernel_name, charp, 0400);
+MODULE_PARM_DESC(backported_kernel_name,
+ "The kernel tree name that was used for this backport (" BACKPORTED_KERNEL_NAME ")");
+
+module_param(backported_kernel_version, charp, 0400);
+MODULE_PARM_DESC(backported_kernel_version,
+ "The kernel version that was used for this backport (" BACKPORTED_KERNEL_VERSION ")");
+
+module_param(backports_version, charp, 0400);
+MODULE_PARM_DESC(backports_version,
+ "The git version of the backports tree used to generate this backport (" BACKPORTS_VERSION ")");
+
+void backport_dependency_symbol(void)
+{
+}
+EXPORT_SYMBOL_GPL(backport_dependency_symbol);
+
+
+static int __init backport_init(void)
+{
+ backport_pm_qos_power_init();
+ backport_system_workqueue_create();
+ backport_init_mmc_pm_flags();
+
+ printk(KERN_INFO "Loading modules backported from " BACKPORTED_KERNEL_NAME " version " BACKPORTED_KERNEL_VERSION "\n");
+ printk(KERN_INFO "Backport generated by backports.git " BACKPORTS_VERSION "\n");
+
+ return 0;
+}
+module_init(backport_init);
+
+static void __exit backport_exit(void)
+{
+ backport_pm_qos_power_deinit();
+ backport_system_workqueue_destroy();
+
+ return;
+}
+module_exit(backport_exit);
+
diff --git a/backport/compat/pm_qos_params.c b/backport/compat/pm_qos_params.c
new file mode 100644
index 00000000..42785ce1
--- /dev/null
+++ b/backport/compat/pm_qos_params.c
@@ -0,0 +1,477 @@
+#include <net/compat.h>
+
+/* This is the backport of pm-qos params for kernels <= 2.6.25 */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
+
+/*
+ * This module exposes the interface to kernel space for specifying
+ * QoS dependencies. It provides infrastructure for registration of:
+ *
+ * Dependents on a QoS value : register requirements
+ * Watchers of QoS value : get notified when target QoS value changes
+ *
+ * This QoS design is best effort based. Dependents register their QoS needs.
+ * Watchers register to keep track of the current QoS needs of the system.
+ *
+ * There are 3 basic classes of QoS parameter: latency, timeout, throughput
+ * each have defined units:
+ * latency: usec
+ * timeout: usec <-- currently not used.
+ * throughput: kbs (kilo byte / sec)
+ *
+ * There are lists of pm_qos_objects each one wrapping requirements, notifiers
+ *
+ * User mode requirements on a QOS parameter register themselves to the
+ * subsystem by opening the device node /dev/... and writing there request to
+ * the node. As long as the process holds a file handle open to the node the
+ * client continues to be accounted for. Upon file release the usermode
+ * requirement is removed and a new qos target is computed. This way when the
+ * requirement that the application has is cleaned up when closes the file
+ * pointer or exits the pm_qos_object will get an opportunity to clean up.
+ *
+ * Mark Gross <mgross@linux.intel.com>
+ */
+
+#include <linux/pm_qos_params.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+
+#include <linux/uaccess.h>
+
+/*
+ * locking rule: all changes to requirements or notifiers lists
+ * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
+ * held, taken with _irqsave. One lock to rule them all
+ */
+struct requirement_list {
+ struct list_head list;
+ union {
+ s32 value;
+ s32 usec;
+ s32 kbps;
+ };
+ char *name;
+};
+
+static s32 max_compare(s32 v1, s32 v2);
+static s32 min_compare(s32 v1, s32 v2);
+
+struct pm_qos_object {
+ struct requirement_list requirements;
+ struct blocking_notifier_head *notifiers;
+ struct miscdevice pm_qos_power_miscdev;
+ char *name;
+ s32 default_value;
+ atomic_t target_value;
+ s32 (*comparitor)(s32, s32);
+};
+
+static struct pm_qos_object null_pm_qos;
+static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
+static struct pm_qos_object cpu_dma_pm_qos = {
+ .requirements = {LIST_HEAD_INIT(cpu_dma_pm_qos.requirements.list)},
+ .notifiers = &cpu_dma_lat_notifier,
+ .name = "cpu_dma_latency",
+ .default_value = 2000 * USEC_PER_SEC,
+ .target_value = ATOMIC_INIT(2000 * USEC_PER_SEC),
+ .comparitor = min_compare
+};
+
+static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
+static struct pm_qos_object network_lat_pm_qos = {
+ .requirements = {LIST_HEAD_INIT(network_lat_pm_qos.requirements.list)},
+ .notifiers = &network_lat_notifier,
+ .name = "network_latency",
+ .default_value = 2000 * USEC_PER_SEC,
+ .target_value = ATOMIC_INIT(2000 * USEC_PER_SEC),
+ .comparitor = min_compare
+};
+
+
+static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
+static struct pm_qos_object network_throughput_pm_qos = {
+ .requirements =
+ {LIST_HEAD_INIT(network_throughput_pm_qos.requirements.list)},
+ .notifiers = &network_throughput_notifier,
+ .name = "network_throughput",
+ .default_value = 0,
+ .target_value = ATOMIC_INIT(0),
+ .comparitor = max_compare
+};
+
+static BLOCKING_NOTIFIER_HEAD(system_bus_freq_notifier);
+static struct pm_qos_object system_bus_freq_pm_qos = {
+ .requirements =
+ {LIST_HEAD_INIT(system_bus_freq_pm_qos.requirements.list)},
+ .notifiers = &system_bus_freq_notifier,
+ .name = "system_bus_freq",
+ .default_value = 0,
+ .target_value = ATOMIC_INIT(0),
+ .comparitor = max_compare
+};
+
+
+static struct pm_qos_object *pm_qos_array[PM_QOS_NUM_CLASSES] = {
+ [PM_QOS_RESERVED] = &null_pm_qos,
+ [PM_QOS_CPU_DMA_LATENCY] = &cpu_dma_pm_qos,
+ [PM_QOS_NETWORK_LATENCY] = &network_lat_pm_qos,
+ [PM_QOS_NETWORK_THROUGHPUT] = &network_throughput_pm_qos,
+ [PM_QOS_SYSTEM_BUS_FREQ] = &system_bus_freq_pm_qos,
+};
+
+static DEFINE_SPINLOCK(pm_qos_lock);
+
+static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos);
+static int pm_qos_power_open(struct inode *inode, struct file *filp);
+static int pm_qos_power_release(struct inode *inode, struct file *filp);
+
+static const struct file_operations pm_qos_power_fops = {
+ .write = pm_qos_power_write,
+ .open = pm_qos_power_open,
+ .release = pm_qos_power_release,
+};
+
+/* static helper functions */
+static s32 max_compare(s32 v1, s32 v2)
+{
+ return max(v1, v2);
+}
+
+static s32 min_compare(s32 v1, s32 v2)
+{
+ return min(v1, v2);
+}
+
+
+static void update_target(int target)
+{
+ s32 extreme_value;
+ struct requirement_list *node;
+ unsigned long flags;
+ int call_notifier = 0;
+
+ spin_lock_irqsave(&pm_qos_lock, flags);
+ extreme_value = pm_qos_array[target]->default_value;
+ list_for_each_entry(node,
+ &pm_qos_array[target]->requirements.list, list) {
+ extreme_value = pm_qos_array[target]->comparitor(
+ extreme_value, node->value);
+ }
+ if (atomic_read(&pm_qos_array[target]->target_value) != extreme_value) {
+ call_notifier = 1;
+ atomic_set(&pm_qos_array[target]->target_value, extreme_value);
+ pr_debug(KERN_ERR "new target for qos %d is %d\n", target,
+ atomic_read(&pm_qos_array[target]->target_value));
+ }
+ spin_unlock_irqrestore(&pm_qos_lock, flags);
+
+ if (call_notifier)
+ blocking_notifier_call_chain(pm_qos_array[target]->notifiers,
+ (unsigned long) extreme_value, NULL);
+}
+
+static int register_pm_qos_misc(struct pm_qos_object *qos)
+{
+ qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
+ qos->pm_qos_power_miscdev.name = qos->name;
+ qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
+
+ return misc_register(&qos->pm_qos_power_miscdev);
+}
+
+static int find_pm_qos_object_by_minor(int minor)
+{
+ int pm_qos_class;
+
+ for (pm_qos_class = 0;
+ pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
+ if (minor ==
+ pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
+ return pm_qos_class;
+ }
+ return -1;
+}
+
+/**
+ * pm_qos_requirement - returns current system wide qos expectation
+ * @pm_qos_class: identification of which qos value is requested
+ *
+ * This function returns the current target value in an atomic manner.
+ */
+int pm_qos_requirement(int pm_qos_class)
+{
+ return atomic_read(&pm_qos_array[pm_qos_class]->target_value);
+}
+EXPORT_SYMBOL_GPL(pm_qos_requirement);
+
+/**
+ * pm_qos_add_requirement - inserts new qos request into the list
+ * @pm_qos_class: identifies which list of qos request to us
+ * @name: identifies the request
+ * @value: defines the qos request
+ *
+ * This function inserts a new entry in the pm_qos_class list of requested qos
+ * performance characteristics. It recomputes the aggregate QoS expectations
+ * for the pm_qos_class of parameters.
+ */
+int pm_qos_add_requirement(int pm_qos_class, char *name, s32 value)
+{
+ struct requirement_list *dep;
+ unsigned long flags;
+
+ dep = kzalloc(sizeof(struct requirement_list), GFP_KERNEL);
+ if (dep) {
+ if (value == PM_QOS_DEFAULT_VALUE)
+ dep->value = pm_qos_array[pm_qos_class]->default_value;
+ else
+ dep->value = value;
+ dep->name = kstrdup(name, GFP_KERNEL);
+ if (!dep->name)
+ goto cleanup;
+
+ spin_lock_irqsave(&pm_qos_lock, flags);
+ list_add(&dep->list,
+ &pm_qos_array[pm_qos_class]->requirements.list);
+ spin_unlock_irqrestore(&pm_qos_lock, flags);
+ update_target(pm_qos_class);
+
+ return 0;
+ }
+
+cleanup:
+ kfree(dep);
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(pm_qos_add_requirement);
+
+/**
+ * pm_qos_update_requirement - modifies an existing qos request
+ * @pm_qos_class: identifies which list of qos request to us
+ * @name: identifies the request
+ * @value: defines the qos request
+ *
+ * Updates an existing qos requirement for the pm_qos_class of parameters along
+ * with updating the target pm_qos_class value.
+ *
+ * If the named request isn't in the list then no change is made.
+ */
+int pm_qos_update_requirement(int pm_qos_class, char *name, s32 new_value)
+{
+ unsigned long flags;
+ struct requirement_list *node;
+ int pending_update = 0;
+
+ spin_lock_irqsave(&pm_qos_lock, flags);
+ list_for_each_entry(node,
+ &pm_qos_array[pm_qos_class]->requirements.list, list) {
+ if (strcmp(node->name, name) == 0) {
+ if (new_value == PM_QOS_DEFAULT_VALUE)
+ node->value =
+ pm_qos_array[pm_qos_class]->default_value;
+ else
+ node->value = new_value;
+ pending_update = 1;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&pm_qos_lock, flags);
+ if (pending_update)
+ update_target(pm_qos_class);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pm_qos_update_requirement);
+
+/**
+ * pm_qos_remove_requirement - modifies an existing qos request
+ * @pm_qos_class: identifies which list of qos request to us
+ * @name: identifies the request
+ *
+ * Will remove named qos request from pm_qos_class list of parameters and
+ * recompute the current target value for the pm_qos_class.
+ */
+void pm_qos_remove_requirement(int pm_qos_class, char *name)
+{
+ unsigned long flags;
+ struct requirement_list *node;
+ int pending_update = 0;
+
+ spin_lock_irqsave(&pm_qos_lock, flags);
+ list_for_each_entry(node,
+ &pm_qos_array[pm_qos_class]->requirements.list, list) {
+ if (strcmp(node->name, name) == 0) {
+ kfree(node->name);
+ list_del(&node->list);
+ kfree(node);
+ pending_update = 1;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&pm_qos_lock, flags);
+ if (pending_update)
+ update_target(pm_qos_class);
+}
+EXPORT_SYMBOL_GPL(pm_qos_remove_requirement);
+
+/**
+ * pm_qos_add_notifier - sets notification entry for changes to target value
+ * @pm_qos_class: identifies which qos target changes should be notified.
+ * @notifier: notifier block managed by caller.
+ *
+ * will register the notifier into a notification chain that gets called
+ * upon changes to the pm_qos_class target value.
+ */
+int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
+{
+ int retval;
+
+ retval = blocking_notifier_chain_register(
+ pm_qos_array[pm_qos_class]->notifiers, notifier);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(pm_qos_add_notifier);
+
+/**
+ * pm_qos_remove_notifier - deletes notification entry from chain.
+ * @pm_qos_class: identifies which qos target changes are notified.
+ * @notifier: notifier block to be removed.
+ *
+ * will remove the notifier from the notification chain that gets called
+ * upon changes to the pm_qos_class target value.
+ */
+int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
+{
+ int retval;
+
+ retval = blocking_notifier_chain_unregister(
+ pm_qos_array[pm_qos_class]->notifiers, notifier);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
+
+#define PID_NAME_LEN 32
+
+static int pm_qos_power_open(struct inode *inode, struct file *filp)
+{
+ int ret;
+ long pm_qos_class;
+ char name[PID_NAME_LEN];
+
+ pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
+ if (pm_qos_class >= 0) {
+ filp->private_data = (void *)pm_qos_class;
+ snprintf(name, PID_NAME_LEN, "process_%d", current->pid);
+ ret = pm_qos_add_requirement(pm_qos_class, name,
+ PM_QOS_DEFAULT_VALUE);
+ if (ret >= 0)
+ return 0;
+ }
+ return -EPERM;
+}
+
+static int pm_qos_power_release(struct inode *inode, struct file *filp)
+{
+ int pm_qos_class;
+ char name[PID_NAME_LEN];
+
+ pm_qos_class = (long)filp->private_data;
+ snprintf(name, PID_NAME_LEN, "process_%d", current->pid);
+ pm_qos_remove_requirement(pm_qos_class, name);
+
+ return 0;
+}
+
+static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ s32 value;
+ int pm_qos_class;
+ char name[PID_NAME_LEN];
+
+ pm_qos_class = (long)filp->private_data;
+ if (count != sizeof(s32))
+ return -EINVAL;
+ if (copy_from_user(&value, buf, sizeof(s32)))
+ return -EFAULT;
+ snprintf(name, PID_NAME_LEN, "process_%d", current->pid);
+ pm_qos_update_requirement(pm_qos_class, name, value);
+
+ return sizeof(s32);
+}
+
+
+/*
+ * This initializes pm-qos for older kernels.
+ */
+int backport_pm_qos_power_init(void)
+{
+ int ret = 0;
+
+ ret = register_pm_qos_misc(&cpu_dma_pm_qos);
+ if (ret < 0) {
+ printk(KERN_ERR "pm_qos_param: cpu_dma_latency setup failed\n");
+ return ret;
+ }
+ ret = register_pm_qos_misc(&network_lat_pm_qos);
+ if (ret < 0) {
+ printk(KERN_ERR "pm_qos_param: network_latency setup failed\n");
+ return ret;
+ }
+ ret = register_pm_qos_misc(&network_throughput_pm_qos);
+ if (ret < 0) {
+ printk(KERN_ERR
+ "pm_qos_param: network_throughput setup failed\n");
+ return ret;
+ }
+ ret = register_pm_qos_misc(&system_bus_freq_pm_qos);
+ if (ret < 0)
+ printk(KERN_ERR
+ "pm_qos_param: system_bus_freq setup failed\n");
+
+ return ret;
+}
+
+int backport_pm_qos_power_deinit(void)
+{
+ int ret = 0;
+
+ ret = misc_deregister(&cpu_dma_pm_qos.pm_qos_power_miscdev);
+ if (ret < 0) {
+ printk(KERN_ERR "pm_qos_param: cpu_dma_latency deinit failed\n");
+ return ret;
+ }
+
+ ret = misc_deregister(&network_lat_pm_qos.pm_qos_power_miscdev);
+ if (ret < 0) {
+ printk(KERN_ERR "pm_qos_param: network_latency deinit failed\n");
+ return ret;
+ }
+
+ ret = misc_deregister(&network_throughput_pm_qos.pm_qos_power_miscdev);
+ if (ret < 0) {
+ printk(KERN_ERR
+ "pm_qos_param: network_throughput deinit failed\n");
+ return ret;
+ }
+
+ ret = misc_deregister(&system_bus_freq_pm_qos.pm_qos_power_miscdev);
+ if (ret < 0) {
+ printk(KERN_ERR
+ "pm_qos_param: system_bus_freq deinit failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) */
diff --git a/backport/compat/sch_codel.c b/backport/compat/sch_codel.c
new file mode 100644
index 00000000..5ad66fbc
--- /dev/null
+++ b/backport/compat/sch_codel.c
@@ -0,0 +1,306 @@
+/*
+ * Codel - The Controlled-Delay Active Queue Management algorithm
+ *
+ * Copyright (C) 2011-2012 Kathleen Nichols <nichols@pollere.com>
+ * Copyright (C) 2011-2012 Van Jacobson <van@pollere.net>
+ *
+ * Implemented on linux by :
+ * Copyright (C) 2012 Michael D. Taht <dave.taht@bufferbloat.net>
+ * Copyright (C) 2012 Eric Dumazet <edumazet@google.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/prefetch.h>
+#include <net/pkt_sched.h>
+#include <net/codel.h>
+
+
+#define DEFAULT_CODEL_LIMIT 1000
+
+struct codel_sched_data {
+ struct codel_params params;
+ struct codel_vars vars;
+ struct codel_stats stats;
+ u32 drop_overlimit;
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ u32 limit;
+#endif
+};
+
+/* This is the specific function called from codel_dequeue()
+ * to dequeue a packet from queue. Note: backlog is handled in
+ * codel, we dont need to reduce it here.
+ */
+static struct sk_buff *dequeue(struct codel_vars *vars, struct Qdisc *sch)
+{
+ struct sk_buff *skb = __skb_dequeue(&sch->q);
+
+ prefetch(&skb->end); /* we'll need skb_shinfo() */
+ return skb;
+}
+
+static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch)
+{
+ struct codel_sched_data *q = qdisc_priv(sch);
+ struct sk_buff *skb;
+
+ skb = codel_dequeue(sch, &q->params, &q->vars, &q->stats, dequeue);
+
+ /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0,
+ * or HTB crashes. Defer it for next round.
+ */
+ if (q->stats.drop_count && sch->q.qlen) {
+ qdisc_tree_decrease_qlen(sch, q->stats.drop_count);
+ q->stats.drop_count = 0;
+ }
+ if (skb)
+ qdisc_bstats_update(sch, skb);
+ return skb;
+}
+
+static int codel_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+ struct codel_sched_data *q;
+
+ q = qdisc_priv(sch);
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ if (likely(qdisc_qlen(sch) < q->limit)) {
+#else
+ if (likely(qdisc_qlen(sch) < sch->limit)) {
+#endif
+ codel_set_enqueue_time(skb);
+ return qdisc_enqueue_tail(skb, sch);
+ }
+ q->drop_overlimit++;
+ return qdisc_drop(skb, sch);
+}
+
+static const struct nla_policy codel_policy[TCA_CODEL_MAX + 1] = {
+ [TCA_CODEL_TARGET] = { .type = NLA_U32 },
+ [TCA_CODEL_LIMIT] = { .type = NLA_U32 },
+ [TCA_CODEL_INTERVAL] = { .type = NLA_U32 },
+ [TCA_CODEL_ECN] = { .type = NLA_U32 },
+};
+
+static int codel_change(struct Qdisc *sch, struct nlattr *opt)
+{
+ struct codel_sched_data *q = qdisc_priv(sch);
+ struct nlattr *tb[TCA_CODEL_MAX + 1];
+ unsigned int qlen;
+ int err;
+
+ if (!opt)
+ return -EINVAL;
+
+ err = nla_parse_nested(tb, TCA_CODEL_MAX, opt, codel_policy);
+ if (err < 0)
+ return err;
+
+ sch_tree_lock(sch);
+
+ if (tb[TCA_CODEL_TARGET]) {
+ u32 target = nla_get_u32(tb[TCA_CODEL_TARGET]);
+
+ q->params.target = ((u64)target * NSEC_PER_USEC) >> CODEL_SHIFT;
+ }
+
+ if (tb[TCA_CODEL_INTERVAL]) {
+ u32 interval = nla_get_u32(tb[TCA_CODEL_INTERVAL]);
+
+ q->params.interval = ((u64)interval * NSEC_PER_USEC) >> CODEL_SHIFT;
+ }
+
+ if (tb[TCA_CODEL_LIMIT])
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ q->limit = nla_get_u32(tb[TCA_CODEL_LIMIT]);
+#else
+ sch->limit = nla_get_u32(tb[TCA_CODEL_LIMIT]);
+#endif
+
+ if (tb[TCA_CODEL_ECN])
+ q->params.ecn = !!nla_get_u32(tb[TCA_CODEL_ECN]);
+
+ qlen = sch->q.qlen;
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ while (sch->q.qlen > q->limit) {
+#else
+ while (sch->q.qlen > sch->limit) {
+#endif
+ struct sk_buff *skb = __skb_dequeue(&sch->q);
+
+ sch->qstats.backlog -= qdisc_pkt_len(skb);
+ qdisc_drop(skb, sch);
+ }
+ qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
+
+ sch_tree_unlock(sch);
+ return 0;
+}
+
+static int codel_init(struct Qdisc *sch, struct nlattr *opt)
+{
+ struct codel_sched_data *q = qdisc_priv(sch);
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ q->limit = DEFAULT_CODEL_LIMIT;
+#else
+ sch->limit = DEFAULT_CODEL_LIMIT;
+#endif
+
+ codel_params_init(&q->params);
+ codel_vars_init(&q->vars);
+ codel_stats_init(&q->stats);
+
+ if (opt) {
+ int err = codel_change(sch, opt);
+
+ if (err)
+ return err;
+ }
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ if (q->limit >= 1)
+#else
+ if (sch->limit >= 1)
+#endif
+ sch->flags |= TCQ_F_CAN_BYPASS;
+ else
+ sch->flags &= ~TCQ_F_CAN_BYPASS;
+
+ return 0;
+}
+
+static int codel_dump(struct Qdisc *sch, struct sk_buff *skb)
+{
+ struct codel_sched_data *q = qdisc_priv(sch);
+ struct nlattr *opts;
+
+ opts = nla_nest_start(skb, TCA_OPTIONS);
+ if (opts == NULL)
+ goto nla_put_failure;
+
+ if (nla_put_u32(skb, TCA_CODEL_TARGET,
+ codel_time_to_us(q->params.target)) ||
+ nla_put_u32(skb, TCA_CODEL_LIMIT,
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ q->limit) ||
+#else
+ sch->limit) ||
+#endif
+ nla_put_u32(skb, TCA_CODEL_INTERVAL,
+ codel_time_to_us(q->params.interval)) ||
+ nla_put_u32(skb, TCA_CODEL_ECN,
+ q->params.ecn))
+ goto nla_put_failure;
+
+ return nla_nest_end(skb, opts);
+
+nla_put_failure:
+ nla_nest_cancel(skb, opts);
+ return -1;
+}
+
+static int codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
+{
+ const struct codel_sched_data *q = qdisc_priv(sch);
+ struct tc_codel_xstats st = {
+ .maxpacket = q->stats.maxpacket,
+ .count = q->vars.count,
+ .lastcount = q->vars.lastcount,
+ .drop_overlimit = q->drop_overlimit,
+ .ldelay = codel_time_to_us(q->vars.ldelay),
+ .dropping = q->vars.dropping,
+ .ecn_mark = q->stats.ecn_mark,
+ };
+
+ if (q->vars.dropping) {
+ codel_tdiff_t delta = q->vars.drop_next - codel_get_time();
+
+ if (delta >= 0)
+ st.drop_next = codel_time_to_us(delta);
+ else
+ st.drop_next = -codel_time_to_us(-delta);
+ }
+
+ return gnet_stats_copy_app(d, &st, sizeof(st));
+}
+
+static void codel_reset(struct Qdisc *sch)
+{
+ struct codel_sched_data *q = qdisc_priv(sch);
+
+ qdisc_reset_queue(sch);
+ codel_vars_init(&q->vars);
+}
+
+static struct Qdisc_ops codel_qdisc_ops __read_mostly = {
+ .id = "codel",
+ .priv_size = sizeof(struct codel_sched_data),
+
+ .enqueue = codel_qdisc_enqueue,
+ .dequeue = codel_qdisc_dequeue,
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28))
+ .peek = qdisc_peek_dequeued,
+#endif
+ .init = codel_init,
+ .reset = codel_reset,
+ .change = codel_change,
+ .dump = codel_dump,
+ .dump_stats = codel_dump_stats,
+ .owner = THIS_MODULE,
+};
+
+static int __init codel_module_init(void)
+{
+ return register_qdisc(&codel_qdisc_ops);
+}
+
+static void __exit codel_module_exit(void)
+{
+ unregister_qdisc(&codel_qdisc_ops);
+}
+
+module_init(codel_module_init)
+module_exit(codel_module_exit)
+
+MODULE_DESCRIPTION("Controlled Delay queue discipline");
+MODULE_AUTHOR("Dave Taht");
+MODULE_AUTHOR("Eric Dumazet");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/backport/compat/sch_fq_codel_core.c b/backport/compat/sch_fq_codel_core.c
new file mode 100644
index 00000000..f03df2ab
--- /dev/null
+++ b/backport/compat/sch_fq_codel_core.c
@@ -0,0 +1,659 @@
+/*
+ * Fair Queue CoDel discipline
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Copyright (C) 2012 Eric Dumazet <edumazet@google.com>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/jhash.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <net/netlink.h>
+#include <net/pkt_sched.h>
+#include <net/flow_keys.h>
+#include <net/codel.h>
+
+/* Fair Queue CoDel.
+ *
+ * Principles :
+ * Packets are classified (internal classifier or external) on flows.
+ * This is a Stochastic model (as we use a hash, several flows
+ * might be hashed on same slot)
+ * Each flow has a CoDel managed queue.
+ * Flows are linked onto two (Round Robin) lists,
+ * so that new flows have priority on old ones.
+ *
+ * For a given flow, packets are not reordered (CoDel uses a FIFO)
+ * head drops only.
+ * ECN capability is on by default.
+ * Low memory footprint (64 bytes per flow)
+ */
+
+struct fq_codel_flow {
+ struct sk_buff *head;
+ struct sk_buff *tail;
+ struct list_head flowchain;
+ int deficit;
+ u32 dropped; /* number of drops (or ECN marks) on this flow */
+ struct codel_vars cvars;
+}; /* please try to keep this structure <= 64 bytes */
+
+struct fq_codel_sched_data {
+ struct tcf_proto *filter_list; /* optional external classifier */
+ struct fq_codel_flow *flows; /* Flows table [flows_cnt] */
+ u32 *backlogs; /* backlog table [flows_cnt] */
+ u32 flows_cnt; /* number of flows */
+ u32 perturbation; /* hash perturbation */
+ u32 quantum; /* psched_mtu(qdisc_dev(sch)); */
+ struct codel_params cparams;
+ struct codel_stats cstats;
+ u32 drop_overlimit;
+ u32 new_flow_count;
+
+ struct list_head new_flows; /* list of new flows */
+ struct list_head old_flows; /* list of old flows */
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ u32 limit;
+#endif
+};
+
+static unsigned int fq_codel_hash(const struct fq_codel_sched_data *q,
+ const struct sk_buff *skb)
+{
+ struct flow_keys keys;
+ unsigned int hash;
+
+ skb_flow_dissect(skb, &keys);
+ hash = jhash_3words((__force u32)keys.dst,
+ (__force u32)keys.src ^ keys.ip_proto,
+ (__force u32)keys.ports, q->perturbation);
+ return ((u64)hash * q->flows_cnt) >> 32;
+}
+
+static unsigned int fq_codel_classify(struct sk_buff *skb, struct Qdisc *sch,
+ int *qerr)
+{
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+ struct tcf_result res;
+ int result;
+
+ if (TC_H_MAJ(skb->priority) == sch->handle &&
+ TC_H_MIN(skb->priority) > 0 &&
+ TC_H_MIN(skb->priority) <= q->flows_cnt)
+ return TC_H_MIN(skb->priority);
+
+ if (!q->filter_list)
+ return fq_codel_hash(q, skb) + 1;
+
+ *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
+ result = tc_classify(skb, q->filter_list, &res);
+ if (result >= 0) {
+#ifdef CONFIG_NET_CLS_ACT
+ switch (result) {
+ case TC_ACT_STOLEN:
+ case TC_ACT_QUEUED:
+ *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
+ case TC_ACT_SHOT:
+ return 0;
+ }
+#endif
+ if (TC_H_MIN(res.classid) <= q->flows_cnt)
+ return TC_H_MIN(res.classid);
+ }
+ return 0;
+}
+
+/* helper functions : might be changed when/if skb use a standard list_head */
+
+/* remove one skb from head of slot queue */
+static inline struct sk_buff *dequeue_head(struct fq_codel_flow *flow)
+{
+ struct sk_buff *skb = flow->head;
+
+ flow->head = skb->next;
+ skb->next = NULL;
+ return skb;
+}
+
+/* add skb to flow queue (tail add) */
+static inline void flow_queue_add(struct fq_codel_flow *flow,
+ struct sk_buff *skb)
+{
+ if (flow->head == NULL)
+ flow->head = skb;
+ else
+ flow->tail->next = skb;
+ flow->tail = skb;
+ skb->next = NULL;
+}
+
+static unsigned int fq_codel_drop(struct Qdisc *sch)
+{
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+ struct sk_buff *skb;
+ unsigned int maxbacklog = 0, idx = 0, i, len;
+ struct fq_codel_flow *flow;
+
+ /* Queue is full! Find the fat flow and drop packet from it.
+ * This might sound expensive, but with 1024 flows, we scan
+ * 4KB of memory, and we dont need to handle a complex tree
+ * in fast path (packet queue/enqueue) with many cache misses.
+ */
+ for (i = 0; i < q->flows_cnt; i++) {
+ if (q->backlogs[i] > maxbacklog) {
+ maxbacklog = q->backlogs[i];
+ idx = i;
+ }
+ }
+ flow = &q->flows[idx];
+ skb = dequeue_head(flow);
+ len = qdisc_pkt_len(skb);
+ q->backlogs[idx] -= len;
+ kfree_skb(skb);
+ sch->q.qlen--;
+ sch->qstats.drops++;
+ sch->qstats.backlog -= len;
+ flow->dropped++;
+ return idx;
+}
+
+static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+ unsigned int idx;
+ struct fq_codel_flow *flow;
+ int uninitialized_var(ret);
+
+ idx = fq_codel_classify(skb, sch, &ret);
+ if (idx == 0) {
+ if (ret & __NET_XMIT_BYPASS)
+ sch->qstats.drops++;
+ kfree_skb(skb);
+ return ret;
+ }
+ idx--;
+
+ codel_set_enqueue_time(skb);
+ flow = &q->flows[idx];
+ flow_queue_add(flow, skb);
+ q->backlogs[idx] += qdisc_pkt_len(skb);
+ sch->qstats.backlog += qdisc_pkt_len(skb);
+
+ if (list_empty(&flow->flowchain)) {
+ list_add_tail(&flow->flowchain, &q->new_flows);
+ codel_vars_init(&flow->cvars);
+ q->new_flow_count++;
+ flow->deficit = q->quantum;
+ flow->dropped = 0;
+ }
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ if (++sch->q.qlen < q->limit)
+#else
+ if (++sch->q.qlen < sch->limit)
+#endif
+ return NET_XMIT_SUCCESS;
+
+ q->drop_overlimit++;
+ /* Return Congestion Notification only if we dropped a packet
+ * from this flow.
+ */
+ if (fq_codel_drop(sch) == idx)
+ return NET_XMIT_CN;
+
+ /* As we dropped a packet, better let upper stack know this */
+ qdisc_tree_decrease_qlen(sch, 1);
+ return NET_XMIT_SUCCESS;
+}
+
+/* This is the specific function called from codel_dequeue()
+ * to dequeue a packet from queue. Note: backlog is handled in
+ * codel, we dont need to reduce it here.
+ */
+static struct sk_buff *dequeue(struct codel_vars *vars, struct Qdisc *sch)
+{
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+ struct fq_codel_flow *flow;
+ struct sk_buff *skb = NULL;
+
+ flow = container_of(vars, struct fq_codel_flow, cvars);
+ if (flow->head) {
+ skb = dequeue_head(flow);
+ q->backlogs[flow - q->flows] -= qdisc_pkt_len(skb);
+ sch->q.qlen--;
+ }
+ return skb;
+}
+
+static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch)
+{
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+ struct sk_buff *skb;
+ struct fq_codel_flow *flow;
+ struct list_head *head;
+ u32 prev_drop_count, prev_ecn_mark;
+
+begin:
+ head = &q->new_flows;
+ if (list_empty(head)) {
+ head = &q->old_flows;
+ if (list_empty(head))
+ return NULL;
+ }
+ flow = list_first_entry(head, struct fq_codel_flow, flowchain);
+
+ if (flow->deficit <= 0) {
+ flow->deficit += q->quantum;
+ list_move_tail(&flow->flowchain, &q->old_flows);
+ goto begin;
+ }
+
+ prev_drop_count = q->cstats.drop_count;
+ prev_ecn_mark = q->cstats.ecn_mark;
+
+ skb = codel_dequeue(sch, &q->cparams, &flow->cvars, &q->cstats,
+ dequeue);
+
+ flow->dropped += q->cstats.drop_count - prev_drop_count;
+ flow->dropped += q->cstats.ecn_mark - prev_ecn_mark;
+
+ if (!skb) {
+ /* force a pass through old_flows to prevent starvation */
+ if ((head == &q->new_flows) && !list_empty(&q->old_flows))
+ list_move_tail(&flow->flowchain, &q->old_flows);
+ else
+ list_del_init(&flow->flowchain);
+ goto begin;
+ }
+ qdisc_bstats_update(sch, skb);
+ flow->deficit -= qdisc_pkt_len(skb);
+ /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0,
+ * or HTB crashes. Defer it for next round.
+ */
+ if (q->cstats.drop_count && sch->q.qlen) {
+ qdisc_tree_decrease_qlen(sch, q->cstats.drop_count);
+ q->cstats.drop_count = 0;
+ }
+ return skb;
+}
+
+static void fq_codel_reset(struct Qdisc *sch)
+{
+ struct sk_buff *skb;
+
+ while ((skb = fq_codel_dequeue(sch)) != NULL)
+ kfree_skb(skb);
+}
+
+static const struct nla_policy fq_codel_policy[TCA_FQ_CODEL_MAX + 1] = {
+ [TCA_FQ_CODEL_TARGET] = { .type = NLA_U32 },
+ [TCA_FQ_CODEL_LIMIT] = { .type = NLA_U32 },
+ [TCA_FQ_CODEL_INTERVAL] = { .type = NLA_U32 },
+ [TCA_FQ_CODEL_ECN] = { .type = NLA_U32 },
+ [TCA_FQ_CODEL_FLOWS] = { .type = NLA_U32 },
+ [TCA_FQ_CODEL_QUANTUM] = { .type = NLA_U32 },
+};
+
+static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt)
+{
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+ struct nlattr *tb[TCA_FQ_CODEL_MAX + 1];
+ int err;
+
+ if (!opt)
+ return -EINVAL;
+
+ err = nla_parse_nested(tb, TCA_FQ_CODEL_MAX, opt, fq_codel_policy);
+ if (err < 0)
+ return err;
+ if (tb[TCA_FQ_CODEL_FLOWS]) {
+ if (q->flows)
+ return -EINVAL;
+ q->flows_cnt = nla_get_u32(tb[TCA_FQ_CODEL_FLOWS]);
+ if (!q->flows_cnt ||
+ q->flows_cnt > 65536)
+ return -EINVAL;
+ }
+ sch_tree_lock(sch);
+
+ if (tb[TCA_FQ_CODEL_TARGET]) {
+ u64 target = nla_get_u32(tb[TCA_FQ_CODEL_TARGET]);
+
+ q->cparams.target = (target * NSEC_PER_USEC) >> CODEL_SHIFT;
+ }
+
+ if (tb[TCA_FQ_CODEL_INTERVAL]) {
+ u64 interval = nla_get_u32(tb[TCA_FQ_CODEL_INTERVAL]);
+
+ q->cparams.interval = (interval * NSEC_PER_USEC) >> CODEL_SHIFT;
+ }
+
+ if (tb[TCA_FQ_CODEL_LIMIT])
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ q->limit = nla_get_u32(tb[TCA_FQ_CODEL_LIMIT]);
+#else
+ sch->limit = nla_get_u32(tb[TCA_FQ_CODEL_LIMIT]);
+#endif
+
+ if (tb[TCA_FQ_CODEL_ECN])
+ q->cparams.ecn = !!nla_get_u32(tb[TCA_FQ_CODEL_ECN]);
+
+ if (tb[TCA_FQ_CODEL_QUANTUM])
+ q->quantum = max(256U, nla_get_u32(tb[TCA_FQ_CODEL_QUANTUM]));
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ while (sch->q.qlen > q->limit) {
+#else
+ while (sch->q.qlen > sch->limit) {
+#endif
+ struct sk_buff *skb = fq_codel_dequeue(sch);
+
+ kfree_skb(skb);
+ q->cstats.drop_count++;
+ }
+ qdisc_tree_decrease_qlen(sch, q->cstats.drop_count);
+ q->cstats.drop_count = 0;
+
+ sch_tree_unlock(sch);
+ return 0;
+}
+
+static void *fq_codel_zalloc(size_t sz)
+{
+ void *ptr = kzalloc(sz, GFP_KERNEL | __GFP_NOWARN);
+
+ if (!ptr)
+ ptr = vzalloc(sz);
+ return ptr;
+}
+
+static void fq_codel_free(void *addr)
+{
+ if (addr) {
+ if (is_vmalloc_addr(addr))
+ vfree(addr);
+ else
+ kfree(addr);
+ }
+}
+
+static void fq_codel_destroy(struct Qdisc *sch)
+{
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25))
+ tcf_destroy_chain(&q->filter_list);
+#else
+ tcf_destroy_chain(q->filter_list);
+#endif
+ fq_codel_free(q->backlogs);
+ fq_codel_free(q->flows);
+}
+
+static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt)
+{
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+ int i;
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ q->limit = 10*1024;
+#else
+ sch->limit = 10*1024;
+#endif
+ q->flows_cnt = 1024;
+ q->quantum = psched_mtu(qdisc_dev(sch));
+ q->perturbation = net_random();
+ INIT_LIST_HEAD(&q->new_flows);
+ INIT_LIST_HEAD(&q->old_flows);
+ codel_params_init(&q->cparams);
+ codel_stats_init(&q->cstats);
+ q->cparams.ecn = true;
+
+ if (opt) {
+ int err = fq_codel_change(sch, opt);
+ if (err)
+ return err;
+ }
+
+ if (!q->flows) {
+ q->flows = fq_codel_zalloc(q->flows_cnt *
+ sizeof(struct fq_codel_flow));
+ if (!q->flows)
+ return -ENOMEM;
+ q->backlogs = fq_codel_zalloc(q->flows_cnt * sizeof(u32));
+ if (!q->backlogs) {
+ fq_codel_free(q->flows);
+ return -ENOMEM;
+ }
+ for (i = 0; i < q->flows_cnt; i++) {
+ struct fq_codel_flow *flow = q->flows + i;
+
+ INIT_LIST_HEAD(&flow->flowchain);
+ }
+ }
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ if (q->limit >= 1)
+#else
+ if (sch->limit >= 1)
+#endif
+ sch->flags |= TCQ_F_CAN_BYPASS;
+ else
+ sch->flags &= ~TCQ_F_CAN_BYPASS;
+ return 0;
+}
+
+static int fq_codel_dump(struct Qdisc *sch, struct sk_buff *skb)
+{
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+ struct nlattr *opts;
+
+ opts = nla_nest_start(skb, TCA_OPTIONS);
+ if (opts == NULL)
+ goto nla_put_failure;
+
+ if (nla_put_u32(skb, TCA_FQ_CODEL_TARGET,
+ codel_time_to_us(q->cparams.target)) ||
+ nla_put_u32(skb, TCA_FQ_CODEL_LIMIT,
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39))
+ q->limit) ||
+#else
+ sch->limit) ||
+#endif
+ nla_put_u32(skb, TCA_FQ_CODEL_INTERVAL,
+ codel_time_to_us(q->cparams.interval)) ||
+ nla_put_u32(skb, TCA_FQ_CODEL_ECN,
+ q->cparams.ecn) ||
+ nla_put_u32(skb, TCA_FQ_CODEL_QUANTUM,
+ q->quantum) ||
+ nla_put_u32(skb, TCA_FQ_CODEL_FLOWS,
+ q->flows_cnt))
+ goto nla_put_failure;
+
+ nla_nest_end(skb, opts);
+ return skb->len;
+
+nla_put_failure:
+ return -1;
+}
+
+static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
+{
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+ struct tc_fq_codel_xstats st = {
+ .type = TCA_FQ_CODEL_XSTATS_QDISC,
+ };
+ struct list_head *pos;
+
+ st.qdisc_stats.maxpacket = q->cstats.maxpacket;
+ st.qdisc_stats.drop_overlimit = q->drop_overlimit;
+ st.qdisc_stats.ecn_mark = q->cstats.ecn_mark;
+ st.qdisc_stats.new_flow_count = q->new_flow_count;
+
+ list_for_each(pos, &q->new_flows)
+ st.qdisc_stats.new_flows_len++;
+
+ list_for_each(pos, &q->old_flows)
+ st.qdisc_stats.old_flows_len++;
+
+ return gnet_stats_copy_app(d, &st, sizeof(st));
+}
+
+static struct Qdisc *fq_codel_leaf(struct Qdisc *sch, unsigned long arg)
+{
+ return NULL;
+}
+
+static unsigned long fq_codel_get(struct Qdisc *sch, u32 classid)
+{
+ return 0;
+}
+
+static unsigned long fq_codel_bind(struct Qdisc *sch, unsigned long parent,
+ u32 classid)
+{
+ /* we cannot bypass queue discipline anymore */
+ sch->flags &= ~TCQ_F_CAN_BYPASS;
+ return 0;
+}
+
+static void fq_codel_put(struct Qdisc *q, unsigned long cl)
+{
+}
+
+static struct tcf_proto **fq_codel_find_tcf(struct Qdisc *sch, unsigned long cl)
+{
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+
+ if (cl)
+ return NULL;
+ return &q->filter_list;
+}
+
+static int fq_codel_dump_class(struct Qdisc *sch, unsigned long cl,
+ struct sk_buff *skb, struct tcmsg *tcm)
+{
+ tcm->tcm_handle |= TC_H_MIN(cl);
+ return 0;
+}
+
+static int fq_codel_dump_class_stats(struct Qdisc *sch, unsigned long cl,
+ struct gnet_dump *d)
+{
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+ u32 idx = cl - 1;
+ struct gnet_stats_queue qs = { 0 };
+ struct tc_fq_codel_xstats xstats;
+
+ if (idx < q->flows_cnt) {
+ const struct fq_codel_flow *flow = &q->flows[idx];
+ const struct sk_buff *skb = flow->head;
+
+ memset(&xstats, 0, sizeof(xstats));
+ xstats.type = TCA_FQ_CODEL_XSTATS_CLASS;
+ xstats.class_stats.deficit = flow->deficit;
+ xstats.class_stats.ldelay =
+ codel_time_to_us(flow->cvars.ldelay);
+ xstats.class_stats.count = flow->cvars.count;
+ xstats.class_stats.lastcount = flow->cvars.lastcount;
+ xstats.class_stats.dropping = flow->cvars.dropping;
+ if (flow->cvars.dropping) {
+ codel_tdiff_t delta = flow->cvars.drop_next -
+ codel_get_time();
+
+ xstats.class_stats.drop_next = (delta >= 0) ?
+ codel_time_to_us(delta) :
+ -codel_time_to_us(-delta);
+ }
+ while (skb) {
+ qs.qlen++;
+ skb = skb->next;
+ }
+ qs.backlog = q->backlogs[idx];
+ qs.drops = flow->dropped;
+ }
+ if (gnet_stats_copy_queue(d, &qs) < 0)
+ return -1;
+ if (idx < q->flows_cnt)
+ return gnet_stats_copy_app(d, &xstats, sizeof(xstats));
+ return 0;
+}
+
+static void fq_codel_walk(struct Qdisc *sch, struct qdisc_walker *arg)
+{
+ struct fq_codel_sched_data *q = qdisc_priv(sch);
+ unsigned int i;
+
+ if (arg->stop)
+ return;
+
+ for (i = 0; i < q->flows_cnt; i++) {
+ if (list_empty(&q->flows[i].flowchain) ||
+ arg->count < arg->skip) {
+ arg->count++;
+ continue;
+ }
+ if (arg->fn(sch, i + 1, arg) < 0) {
+ arg->stop = 1;
+ break;
+ }
+ arg->count++;
+ }
+}
+
+static const struct Qdisc_class_ops fq_codel_class_ops = {
+ .leaf = fq_codel_leaf,
+ .get = fq_codel_get,
+ .put = fq_codel_put,
+ .tcf_chain = fq_codel_find_tcf,
+ .bind_tcf = fq_codel_bind,
+ .unbind_tcf = fq_codel_put,
+ .dump = fq_codel_dump_class,
+ .dump_stats = fq_codel_dump_class_stats,
+ .walk = fq_codel_walk,
+};
+
+static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = {
+ .cl_ops = &fq_codel_class_ops,
+ .id = "fq_codel",
+ .priv_size = sizeof(struct fq_codel_sched_data),
+ .enqueue = fq_codel_enqueue,
+ .dequeue = fq_codel_dequeue,
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28))
+ .peek = qdisc_peek_dequeued,
+#endif
+ .drop = fq_codel_drop,
+ .init = fq_codel_init,
+ .reset = fq_codel_reset,
+ .destroy = fq_codel_destroy,
+ .change = fq_codel_change,
+ .dump = fq_codel_dump,
+ .dump_stats = fq_codel_dump_stats,
+ .owner = THIS_MODULE,
+};
+
+static int __init fq_codel_module_init(void)
+{
+ return register_qdisc(&fq_codel_qdisc_ops);
+}
+
+static void __exit fq_codel_module_exit(void)
+{
+ unregister_qdisc(&fq_codel_qdisc_ops);
+}
+
+module_init(fq_codel_module_init)
+module_exit(fq_codel_module_exit)
+MODULE_AUTHOR("Eric Dumazet");
+MODULE_LICENSE("GPL");
diff --git a/backport/compat/user_namespace.c b/backport/compat/user_namespace.c
new file mode 100644
index 00000000..0dcc4bcf
--- /dev/null
+++ b/backport/compat/user_namespace.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2012 Luis R. Rodriguez <mcgrof@do-not-panic.com>
+ *
+ * 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 backporting
+ * user_namespace.c
+ */
+
+#include <linux/module.h>
+#include <linux/highuid.h>
+#include <linux/user_namespace.h>
+
+#ifdef CONFIG_USER_NS
+
+kuid_t make_kuid(struct user_namespace *ns, uid_t uid)
+{
+ /* Map the uid to a global kernel uid */
+ return KUIDT_INIT(uid);
+}
+EXPORT_SYMBOL_GPL(make_kuid);
+
+uid_t from_kuid(struct user_namespace *targ, kuid_t kuid)
+{
+ /* Map the uid from a global kernel uid */
+ return __kuid_val(kuid);
+}
+EXPORT_SYMBOL_GPL(from_kuid);
+
+uid_t from_kuid_munged(struct user_namespace *targ, kuid_t kuid)
+{
+ uid_t uid;
+ uid = from_kuid(targ, kuid);
+
+ if (uid == (uid_t) -1)
+ uid = overflowuid;
+ return uid;
+}
+EXPORT_SYMBOL_GPL(from_kuid_munged);
+
+kgid_t make_kgid(struct user_namespace *ns, gid_t gid)
+{
+ /* Map the gid to a global kernel gid */
+ return KGIDT_INIT(gid);
+}
+EXPORT_SYMBOL_GPL(make_kgid);
+
+gid_t from_kgid(struct user_namespace *targ, kgid_t kgid)
+{
+ /* Map the gid from a global kernel gid */
+ return __kgid_val(kgid);
+}
+EXPORT_SYMBOL_GPL(from_kgid);
+
+gid_t from_kgid_munged(struct user_namespace *targ, kgid_t kgid)
+{
+ gid_t gid;
+ gid = from_kgid(targ, kgid);
+
+ if (gid == (gid_t) -1)
+ gid = overflowgid;
+ return gid;
+}
+EXPORT_SYMBOL_GPL(from_kgid_munged);
+
+#endif /* CONFIG_USER_NS */