aboutsummaryrefslogtreecommitdiffstats
diff options
-rw-r--r--driver-core/firmware-class-export-nowait-to-userspace.patch104
-rw-r--r--driver-core/firmware-loader-do-not-allocate-firmare-id-separately.patch77
-rw-r--r--driver-core/firmware-loader-rely-on-driver-core-to-create-class-attribute.patch111
-rw-r--r--driver-core/firmware-loader-split-out-builtin-firmware-handling.patch136
-rw-r--r--series39
-rw-r--r--staging/staging-hv-fix-a-bug-affecting-ipv6.patch35
-rw-r--r--staging/staging-hv-fix-up-memory-leak-on-hvcleanup.patch34
-rw-r--r--staging/staging-hv-name-network-device-ethx-rather-than-sethx.patch36
-rw-r--r--staging/staging-iio-adc-fix-dangling-pointers.patch39
-rw-r--r--staging/staging-iio-function-iio_get_new_idr_val-return-negative-value-if-fails.patch39
-rw-r--r--staging/staging-iio-light-fix-dangling-pointers.patch39
-rw-r--r--staging/staging-iio-lis3l02dq-incorrect-ws-used-in-container-of-call.patch33
-rw-r--r--staging/staging-iio-ring_sw-fix-incorrect-test-on-successful-read-of-last-value-causes-infinite-loop.patch31
-rw-r--r--staging/staging-iio-test-for-failed-allocation.patch32
-rw-r--r--staging/staging-intel-restricted-access-region-handler.patch1821
-rw-r--r--staging/staging-rtl8192su-add-usb-id-for-0bda-8171.patch26
-rw-r--r--tty/serial-add-driver-for-the-altera-jtag-uart.patch596
-rw-r--r--tty/serial-add-driver-for-the-altera-uart.patch668
-rw-r--r--tty/serial-bfin_sport_uart-add-missing-mapbase-initialization.patch40
-rw-r--r--tty/serial-bfin_sport_uart-add-support-for-cts-rts-via-gpios.patch263
-rw-r--r--tty/serial-bfin_sport_uart-drop-redundant-cpu-depends.patch29
-rw-r--r--tty/serial-bfin_sport_uart-drop-the-experimental-markings.patch31
-rw-r--r--tty/serial-bfin_sport_uart-drop-useless-status-masks.patch50
-rw-r--r--tty/serial-bfin_sport_uart-only-enable-sport-tx-if-data-is-to-be-sent.patch107
-rw-r--r--tty/serial-bfin_sport_uart-protect-changes-to-uart_port.patch42
-rw-r--r--tty/serial-bfin_sport_uart-pull-in-bfin_sport.h-for-sport-defines.patch28
-rw-r--r--tty/serial-bfin_sport_uart-remove-unused-peripheral-pin-lists.patch51
-rw-r--r--tty/serial-bfin_sport_uart-rename-early-platform-driver-class-string.patch52
-rw-r--r--tty/serial-bfin_sport_uart-shorten-the-sport-tx-waiting-loop.patch41
-rw-r--r--tty/serial-bfin_sport_uart-work-around-anomaly-05000473-make-32bit-fifo-read-atomic.patch49
-rw-r--r--tty/serial-bfin_sport_uart-zero-sport_uart_port-if-allocated-dynamically.patch37
-rw-r--r--tty/serial-tty-new-ldiscs-for-staging.patch32
-rw-r--r--usb/usb-add-a-new-quirk-usb_quirk_honor_bnuminterfaces.patch100
-rw-r--r--usb/usb-fix-serial-build-when-sysrq-is-disabled.patch54
-rw-r--r--usb/usb-serial-driver-zio-motherboard.patch112
-rw-r--r--version2
36 files changed, 5014 insertions, 2 deletions
diff --git a/driver-core/firmware-class-export-nowait-to-userspace.patch b/driver-core/firmware-class-export-nowait-to-userspace.patch
new file mode 100644
index 00000000000000..6a5b85c5a81d8e
--- /dev/null
+++ b/driver-core/firmware-class-export-nowait-to-userspace.patch
@@ -0,0 +1,104 @@
+From johannes@sipsolutions.net Thu Apr 22 16:48:27 2010
+From: Johannes Berg <johannes@sipsolutions.net>
+Date: Mon, 29 Mar 2010 17:57:20 +0200
+Subject: firmware class: export nowait to userspace
+To: Kay Sievers <kay.sievers@vrfy.org>
+Cc: Tomas Winkler <tomasw@gmail.com>, Greg KH <greg@kroah.com>, David Woodhouse <dwmw2@infradead.org>
+Message-ID: <1269878240.4131.45.camel@jlt3.sipsolutions.net>
+
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+When we use request_firmware_nowait(), userspace may
+not want to answer negatively right away when for
+example it is answering from an initrd only, but
+with request_firmware() it has to in order to not
+delay the kernel boot until the request times out.
+
+This allows userspace to differentiate between the
+two in order to be able to reply negatively to async
+requests only when all filesystems have been mounted
+and have been checked for the requested firmware file.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Cc: Kay Sievers <kay.sievers@vrfy.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/base/firmware_class.c | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+--- a/drivers/base/firmware_class.c
++++ b/drivers/base/firmware_class.c
+@@ -50,6 +50,7 @@ struct firmware_priv {
+ int page_array_size;
+ const char *vdata;
+ struct timer_list timeout;
++ bool nowait;
+ };
+
+ #ifdef CONFIG_FW_LOADER
+@@ -112,6 +113,8 @@ static int firmware_uevent(struct device
+ 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;
+ }
+@@ -427,7 +430,7 @@ error_kfree:
+
+ static int fw_setup_device(struct firmware *fw, struct device **dev_p,
+ const char *fw_name, struct device *device,
+- int uevent)
++ int uevent, bool nowait)
+ {
+ struct device *f_dev;
+ struct firmware_priv *fw_priv;
+@@ -443,6 +446,8 @@ static int fw_setup_device(struct firmwa
+
+ fw_priv = dev_get_drvdata(f_dev);
+
++ fw_priv->nowait = nowait;
++
+ fw_priv->fw = fw;
+ sysfs_bin_attr_init(&fw_priv->attr_data);
+ retval = sysfs_create_bin_file(&f_dev->kobj, &fw_priv->attr_data);
+@@ -470,7 +475,7 @@ out:
+
+ static int
+ _request_firmware(const struct firmware **firmware_p, const char *name,
+- struct device *device, int uevent)
++ struct device *device, int uevent, bool nowait)
+ {
+ struct device *f_dev;
+ struct firmware_priv *fw_priv;
+@@ -502,7 +507,8 @@ _request_firmware(const struct firmware
+ if (uevent)
+ dev_dbg(device, "firmware: requesting %s\n", name);
+
+- retval = fw_setup_device(firmware, &f_dev, name, device, uevent);
++ retval = fw_setup_device(firmware, &f_dev, name, device,
++ uevent, nowait);
+ if (retval)
+ goto error_kfree_fw;
+
+@@ -559,7 +565,7 @@ request_firmware(const struct firmware *
+ struct device *device)
+ {
+ int uevent = 1;
+- return _request_firmware(firmware_p, name, device, uevent);
++ return _request_firmware(firmware_p, name, device, uevent, false);
+ }
+
+ /**
+@@ -605,7 +611,7 @@ request_firmware_work_func(void *arg)
+ return 0;
+ }
+ ret = _request_firmware(&fw, fw_work->name, fw_work->device,
+- fw_work->uevent);
++ fw_work->uevent, true);
+
+ fw_work->cont(fw, fw_work->context);
+
diff --git a/driver-core/firmware-loader-do-not-allocate-firmare-id-separately.patch b/driver-core/firmware-loader-do-not-allocate-firmare-id-separately.patch
new file mode 100644
index 00000000000000..67ffdf600a2c29
--- /dev/null
+++ b/driver-core/firmware-loader-do-not-allocate-firmare-id-separately.patch
@@ -0,0 +1,77 @@
+From dmitry.torokhov@gmail.com Thu Apr 22 16:56:48 2010
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Sat, 13 Mar 2010 23:49:23 -0800
+Subject: [PATCH 4/5] firmware loader: do not allocate firmare id separately
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org
+Message-ID: <20100314074923.27035.81487.stgit@localhost.localdomain>
+
+
+fw_id has the same life time as firmware_priv so it makes sense to move
+it into firmware_priv structure instead of allocating separately.
+
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/base/firmware_class.c | 17 ++++-------------
+ 1 file changed, 4 insertions(+), 13 deletions(-)
+
+--- a/drivers/base/firmware_class.c
++++ b/drivers/base/firmware_class.c
+@@ -86,7 +86,6 @@ static int loading_timeout = 60; /* In s
+ static DEFINE_MUTEX(fw_lock);
+
+ struct firmware_priv {
+- char *fw_id;
+ struct completion completion;
+ struct bin_attribute attr_data;
+ struct firmware *fw;
+@@ -94,9 +93,9 @@ struct firmware_priv {
+ struct page **pages;
+ int nr_pages;
+ int page_array_size;
+- const char *vdata;
+ struct timer_list timeout;
+ bool nowait;
++ char fw_id[];
+ };
+
+ static void
+@@ -153,7 +152,6 @@ static void fw_dev_release(struct device
+ for (i = 0; i < fw_priv->nr_pages; i++)
+ __free_page(fw_priv->pages[i]);
+ kfree(fw_priv->pages);
+- kfree(fw_priv->fw_id);
+ kfree(fw_priv);
+ kfree(dev);
+
+@@ -423,8 +421,8 @@ static int fw_register_device(struct dev
+ struct device *device)
+ {
+ int retval;
+- struct firmware_priv *fw_priv = kzalloc(sizeof(*fw_priv),
+- GFP_KERNEL);
++ struct firmware_priv *fw_priv =
++ kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
+ struct device *f_dev = kzalloc(sizeof(*f_dev), GFP_KERNEL);
+
+ *dev_p = NULL;
+@@ -435,16 +433,9 @@ static int fw_register_device(struct dev
+ goto error_kfree;
+ }
+
++ strcpy(fw_priv->fw_id, fw_name);
+ init_completion(&fw_priv->completion);
+ fw_priv->attr_data = firmware_attr_data_tmpl;
+- fw_priv->fw_id = kstrdup(fw_name, GFP_KERNEL);
+- if (!fw_priv->fw_id) {
+- dev_err(device, "%s: Firmware name allocation failed\n",
+- __func__);
+- retval = -ENOMEM;
+- goto error_kfree;
+- }
+-
+ fw_priv->timeout.function = firmware_class_timeout;
+ fw_priv->timeout.data = (u_long) fw_priv;
+ init_timer(&fw_priv->timeout);
diff --git a/driver-core/firmware-loader-rely-on-driver-core-to-create-class-attribute.patch b/driver-core/firmware-loader-rely-on-driver-core-to-create-class-attribute.patch
new file mode 100644
index 00000000000000..f261ff3f413a25
--- /dev/null
+++ b/driver-core/firmware-loader-rely-on-driver-core-to-create-class-attribute.patch
@@ -0,0 +1,111 @@
+From dmitry.torokhov@gmail.com Thu Apr 22 16:51:51 2010
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Sat, 13 Mar 2010 23:49:13 -0800
+Subject: firmware loader: rely on driver core to create class attribute
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org
+Message-ID: <20100314074913.27035.39475.stgit@localhost.localdomain>
+
+
+Do not create 'timeout' attribute manually, let driver core do it for us.
+This also ensures that attribute is cleaned up properly.
+
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/base/firmware_class.c | 59 +++++++++++++++++-------------------------
+ 1 file changed, 24 insertions(+), 35 deletions(-)
+
+--- a/drivers/base/firmware_class.c
++++ b/drivers/base/firmware_class.c
+@@ -101,9 +101,26 @@ firmware_timeout_store(struct class *cla
+ return count;
+ }
+
+-static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store);
++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);
++static void fw_dev_release(struct device *dev)
++{
++ struct firmware_priv *fw_priv = dev_get_drvdata(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->fw_id);
++ kfree(fw_priv);
++ kfree(dev);
++
++ module_put(THIS_MODULE);
++}
+
+ static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
+ {
+@@ -121,6 +138,7 @@ static int firmware_uevent(struct device
+
+ static struct class firmware_class = {
+ .name = "firmware",
++ .class_attrs = firmware_class_attrs,
+ .dev_uevent = firmware_uevent,
+ .dev_release = fw_dev_release,
+ };
+@@ -356,21 +374,6 @@ static struct bin_attribute firmware_att
+ .write = firmware_data_write,
+ };
+
+-static void fw_dev_release(struct device *dev)
+-{
+- struct firmware_priv *fw_priv = dev_get_drvdata(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->fw_id);
+- kfree(fw_priv);
+- kfree(dev);
+-
+- module_put(THIS_MODULE);
+-}
+-
+ static void
+ firmware_class_timeout(u_long data)
+ {
+@@ -675,26 +678,12 @@ request_firmware_nowait(
+ return 0;
+ }
+
+-static int __init
+-firmware_class_init(void)
++static int __init firmware_class_init(void)
+ {
+- int error;
+- error = class_register(&firmware_class);
+- if (error) {
+- printk(KERN_ERR "%s: class_register failed\n", __func__);
+- return error;
+- }
+- error = class_create_file(&firmware_class, &class_attr_timeout);
+- if (error) {
+- printk(KERN_ERR "%s: class_create_file failed\n",
+- __func__);
+- class_unregister(&firmware_class);
+- }
+- return error;
+-
++ return class_register(&firmware_class);
+ }
+-static void __exit
+-firmware_class_exit(void)
++
++static void __exit firmware_class_exit(void)
+ {
+ class_unregister(&firmware_class);
+ }
diff --git a/driver-core/firmware-loader-split-out-builtin-firmware-handling.patch b/driver-core/firmware-loader-split-out-builtin-firmware-handling.patch
new file mode 100644
index 00000000000000..2f8ce7be128a28
--- /dev/null
+++ b/driver-core/firmware-loader-split-out-builtin-firmware-handling.patch
@@ -0,0 +1,136 @@
+From dmitry.torokhov@gmail.com Thu Apr 22 16:54:41 2010
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Sat, 13 Mar 2010 23:49:18 -0800
+Subject: firmware loader: split out builtin firmware handling
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org
+Message-ID: <20100314074918.27035.80164.stgit@localhost.localdomain>
+
+
+Split builtin firmware handling into separate functions to clean up the
+main body of code.
+
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/base/firmware_class.c | 77 +++++++++++++++++++++++++++---------------
+ 1 file changed, 51 insertions(+), 26 deletions(-)
+
+--- a/drivers/base/firmware_class.c
++++ b/drivers/base/firmware_class.c
+@@ -27,6 +27,52 @@ MODULE_AUTHOR("Manuel Estrada Sainz");
+ MODULE_DESCRIPTION("Multi purpose firmware loading support");
+ MODULE_LICENSE("GPL");
+
++/* Builtin firmware support */
++
++#ifdef CONFIG_FW_LOADER
++
++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,
+@@ -53,14 +99,6 @@ struct firmware_priv {
+ bool nowait;
+ };
+
+-#ifdef CONFIG_FW_LOADER
+-extern struct builtin_fw __start_builtin_fw[];
+-extern struct builtin_fw __end_builtin_fw[];
+-#else /* Module case. Avoid ifdefs later; it'll all optimise out */
+-static struct builtin_fw *__start_builtin_fw;
+-static struct builtin_fw *__end_builtin_fw;
+-#endif
+-
+ static void
+ fw_load_abort(struct firmware_priv *fw_priv)
+ {
+@@ -483,7 +521,6 @@ _request_firmware(const struct firmware
+ struct device *f_dev;
+ struct firmware_priv *fw_priv;
+ struct firmware *firmware;
+- struct builtin_fw *builtin;
+ int retval;
+
+ if (!firmware_p)
+@@ -497,13 +534,8 @@ _request_firmware(const struct firmware
+ goto out;
+ }
+
+- for (builtin = __start_builtin_fw; builtin != __end_builtin_fw;
+- builtin++) {
+- if (strcmp(name, builtin->name))
+- continue;
++ if (fw_get_builtin_firmware(firmware, name)) {
+ dev_dbg(device, "firmware: using built-in firmware %s\n", name);
+- firmware->size = builtin->size;
+- firmware->data = builtin->data;
+ return 0;
+ }
+
+@@ -575,19 +607,12 @@ request_firmware(const struct firmware *
+ * release_firmware: - release the resource associated with a firmware image
+ * @fw: firmware resource to release
+ **/
+-void
+-release_firmware(const struct firmware *fw)
++void release_firmware(const struct firmware *fw)
+ {
+- struct builtin_fw *builtin;
+-
+ if (fw) {
+- for (builtin = __start_builtin_fw; builtin != __end_builtin_fw;
+- builtin++) {
+- if (fw->data == builtin->data)
+- goto free_fw;
+- }
+- vfree(fw->data);
+- free_fw:
++ if (!fw_is_builtin_firmware(fw))
++ vfree(fw->data);
++
+ kfree(fw);
+ }
+ }
diff --git a/series b/series
index 62d46e3fecc479..f86836b19c93f1 100644
--- a/series
+++ b/series
@@ -58,9 +58,30 @@ driver-core/platform_bus-allow-custom-extensions-to-system-pm-methods.patch
driver-core/drivers-base-convert-sema.patch
driver-core/lockdep-add-novalidate-class-for-dev-mutex-conversion.patch
+driver-core/firmware-class-export-nowait-to-userspace.patch
+driver-core/firmware-loader-rely-on-driver-core-to-create-class-attribute.patch
+driver-core/firmware-loader-split-out-builtin-firmware-handling.patch
+driver-core/firmware-loader-do-not-allocate-firmare-id-separately.patch
+
#####################################
# TTY patches for after 2.6.34 is out
#####################################
+tty/serial-add-driver-for-the-altera-jtag-uart.patch
+tty/serial-add-driver-for-the-altera-uart.patch
+tty/serial-bfin_sport_uart-work-around-anomaly-05000473-make-32bit-fifo-read-atomic.patch
+tty/serial-bfin_sport_uart-shorten-the-sport-tx-waiting-loop.patch
+tty/serial-bfin_sport_uart-remove-unused-peripheral-pin-lists.patch
+tty/serial-bfin_sport_uart-add-missing-mapbase-initialization.patch
+tty/serial-bfin_sport_uart-rename-early-platform-driver-class-string.patch
+tty/serial-bfin_sport_uart-add-support-for-cts-rts-via-gpios.patch
+tty/serial-bfin_sport_uart-protect-changes-to-uart_port.patch
+tty/serial-bfin_sport_uart-zero-sport_uart_port-if-allocated-dynamically.patch
+tty/serial-bfin_sport_uart-drop-useless-status-masks.patch
+tty/serial-bfin_sport_uart-only-enable-sport-tx-if-data-is-to-be-sent.patch
+tty/serial-bfin_sport_uart-pull-in-bfin_sport.h-for-sport-defines.patch
+tty/serial-bfin_sport_uart-drop-the-experimental-markings.patch
+tty/serial-bfin_sport_uart-drop-redundant-cpu-depends.patch
+tty/serial-tty-new-ldiscs-for-staging.patch
@@ -86,11 +107,27 @@ usb/usb-musb-gadget-support-musb-specific-test-modes.patch
usb/usb-musb-hsdma-use-musb_read-writel.patch
usb/usb-f_mass_storage-dynamic-buffers-for-better-alignment.patch
usb/usb-console-pass-baud-from-console-to-the-initial-tty-open.patch
+usb/usb-serial-driver-zio-motherboard.patch
+usb/usb-fix-serial-build-when-sysrq-is-disabled.patch
+usb/usb-add-a-new-quirk-usb_quirk_honor_bnuminterfaces.patch
#######################################
# Staging stuff for after 2.6.34 is out
#######################################
-
+# bugfixes
+staging/staging-iio-lis3l02dq-incorrect-ws-used-in-container-of-call.patch
+staging/staging-iio-test-for-failed-allocation.patch
+staging/staging-iio-light-fix-dangling-pointers.patch
+staging/staging-iio-adc-fix-dangling-pointers.patch
+staging/staging-iio-function-iio_get_new_idr_val-return-negative-value-if-fails.patch
+staging/staging-iio-ring_sw-fix-incorrect-test-on-successful-read-of-last-value-causes-infinite-loop.patch
+staging/staging-hv-fix-a-bug-affecting-ipv6.patch
+staging/staging-hv-fix-up-memory-leak-on-hvcleanup.patch
+staging/staging-hv-name-network-device-ethx-rather-than-sethx.patch
+staging/staging-rtl8192su-add-usb-id-for-0bda-8171.patch
+
+# new stuff
+staging/staging-intel-restricted-access-region-handler.patch
diff --git a/staging/staging-hv-fix-a-bug-affecting-ipv6.patch b/staging/staging-hv-fix-a-bug-affecting-ipv6.patch
new file mode 100644
index 00000000000000..ccbffe697d7ca2
--- /dev/null
+++ b/staging/staging-hv-fix-a-bug-affecting-ipv6.patch
@@ -0,0 +1,35 @@
+From haiyangz@microsoft.com Thu Apr 22 16:42:47 2010
+From: Haiyang Zhang <haiyangz@microsoft.com>
+Date: Mon, 19 Apr 2010 15:32:11 +0000
+Subject: Staging: hv: Fix a bug affecting IPv6
+To: Greg KH <gregkh@suse.de>
+Cc: Hank Janssen <hjanssen@microsoft.com>, Toshikazu Sakai <Toshikazu.Sakai@microsoft.com>
+Message-ID: <1FB5E1D5CA062146B38059374562DF7266281C0D@TK5EX14MBXC121.redmond.corp.microsoft.com>
+
+
+From: Haiyang Zhang <haiyangz@microsoft.com>
+
+Fix a bug affecting IPv6
+Added the multicast flag for proper IPv6 function.
+
+Reported-by: Toshikazu Sakai <toshikas@microsoft.com>
+Signed-off-by: Hank Janssen <hjanssen@microsoft.com>
+Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/staging/hv/RndisFilter.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/staging/hv/RndisFilter.c
++++ b/drivers/staging/hv/RndisFilter.c
+@@ -751,6 +751,7 @@ static int RndisFilterOpenDevice(struct
+
+ ret = RndisFilterSetPacketFilter(Device,
+ NDIS_PACKET_TYPE_BROADCAST |
++ NDIS_PACKET_TYPE_ALL_MULTICAST |
+ NDIS_PACKET_TYPE_DIRECTED);
+ if (ret == 0)
+ Device->State = RNDIS_DEV_DATAINITIALIZED;
diff --git a/staging/staging-hv-fix-up-memory-leak-on-hvcleanup.patch b/staging/staging-hv-fix-up-memory-leak-on-hvcleanup.patch
new file mode 100644
index 00000000000000..fcbca7fec636a7
--- /dev/null
+++ b/staging/staging-hv-fix-up-memory-leak-on-hvcleanup.patch
@@ -0,0 +1,34 @@
+From gorcunov@openvz.org Thu Apr 22 16:43:51 2010
+From: Cyrill Gorcunov <gorcunov@openvz.org>
+Date: Mon, 5 Apr 2010 20:56:57 +0400
+Subject: Staging: hv: Fix up memory leak on HvCleanup
+To: Greg KH <greg@kroah.com>
+Cc: Haiyang Zhang <haiyangz@microsoft.com>, Hank Janssen <hjanssen@microsoft.com>
+Message-ID: <20100405165657.GE5079@lenovo>
+Content-Disposition: inline
+
+Don't assign NULL too early
+
+Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
+Cc: Hank Janssen <hjanssen@microsoft.com>
+Cc: Haiyang Zhang <haiyangz@microsoft.com>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/hv/Hv.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/hv/Hv.c
++++ b/drivers/staging/hv/Hv.c
+@@ -306,9 +306,9 @@ void HvCleanup(void)
+ DPRINT_ENTER(VMBUS);
+
+ if (gHvContext.SignalEventBuffer) {
++ kfree(gHvContext.SignalEventBuffer);
+ gHvContext.SignalEventBuffer = NULL;
+ gHvContext.SignalEventParam = NULL;
+- kfree(gHvContext.SignalEventBuffer);
+ }
+
+ if (gHvContext.HypercallPage) {
diff --git a/staging/staging-hv-name-network-device-ethx-rather-than-sethx.patch b/staging/staging-hv-name-network-device-ethx-rather-than-sethx.patch
new file mode 100644
index 00000000000000..1c47b2da66785f
--- /dev/null
+++ b/staging/staging-hv-name-network-device-ethx-rather-than-sethx.patch
@@ -0,0 +1,36 @@
+From shemminger@vyatta.com Thu Apr 22 16:45:06 2010
+From: Stephen Hemminger <shemminger@vyatta.com>
+Date: Thu, 11 Mar 2010 09:11:37 -0800
+Subject: Staging: hv: name network device ethX rather than sethX
+To: Hank Janssen <hjanssen@microsoft.com>
+Cc: Greg KH <gregkh@suse.de>, netdev@vger.kernel.org
+Message-ID: <20100311091137.27f22c57@nehalam>
+
+
+This patch makes the HyperV network device use the same naming scheme as
+other virtual drivers (Xen, KVM). In an ideal world, userspace tools
+would not care what the name is, but some users and applications do
+care. Vyatta CLI is one of the tools that does depend on what the name
+is.
+
+Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
+Cc: Hank Janssen <hjanssen@microsoft.com>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/hv/netvsc_drv.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/staging/hv/netvsc_drv.c
++++ b/drivers/staging/hv/netvsc_drv.c
+@@ -403,8 +403,7 @@ static int netvsc_probe(struct device *d
+ if (!net_drv_obj->Base.OnDeviceAdd)
+ return -1;
+
+- net = alloc_netdev(sizeof(struct net_device_context), "seth%d",
+- ether_setup);
++ net = alloc_etherdev(sizeof(struct net_device_context));
+ if (!net)
+ return -1;
+
diff --git a/staging/staging-iio-adc-fix-dangling-pointers.patch b/staging/staging-iio-adc-fix-dangling-pointers.patch
new file mode 100644
index 00000000000000..e0b8620630b654
--- /dev/null
+++ b/staging/staging-iio-adc-fix-dangling-pointers.patch
@@ -0,0 +1,39 @@
+From w.sang@pengutronix.de Thu Apr 22 16:39:35 2010
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Sat, 20 Mar 2010 15:13:02 +0100
+Subject: Staging: iio: adc: fix dangling pointers
+To: kernel-janitors@vger.kernel.org
+Cc: devel@driverdev.osuosl.org, Wolfram Sang <w.sang@pengutronix.de>, Greg Kroah-Hartman <gregkh@suse.de>, linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org
+Message-ID: <1269094385-16114-22-git-send-email-w.sang@pengutronix.de>
+
+
+Fix I2C-drivers which missed setting clientdata to NULL before freeing the
+structure it points to. Also fix drivers which do this _after_ the structure
+was freed already.
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/iio/adc/max1363_core.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/staging/iio/adc/max1363_core.c
++++ b/drivers/staging/iio/adc/max1363_core.c
+@@ -557,6 +557,7 @@ error_put_reg:
+ if (!IS_ERR(st->reg))
+ regulator_put(st->reg);
+ error_free_st:
++ i2c_set_clientdata(client, NULL);
+ kfree(st);
+
+ error_ret:
+@@ -574,6 +575,7 @@ static int max1363_remove(struct i2c_cli
+ regulator_disable(st->reg);
+ regulator_put(st->reg);
+ }
++ i2c_set_clientdata(client, NULL);
+ kfree(st);
+
+ return 0;
diff --git a/staging/staging-iio-function-iio_get_new_idr_val-return-negative-value-if-fails.patch b/staging/staging-iio-function-iio_get_new_idr_val-return-negative-value-if-fails.patch
new file mode 100644
index 00000000000000..d9e6898ac174a9
--- /dev/null
+++ b/staging/staging-iio-function-iio_get_new_idr_val-return-negative-value-if-fails.patch
@@ -0,0 +1,39 @@
+From jic23@cam.ac.uk Thu Apr 22 16:40:17 2010
+From: Sonic Zhang <sonic.adi@gmail.com>
+Date: Mon, 22 Mar 2010 12:27:05 +0000
+Subject: staging: iio: Function iio_get_new_idr_val() return negative value if fails.
+To: sonic zhang <sonic.adi@gmail.com>
+Cc: Linux Kernel <linux-kernel@vger.kernel.org>, linux-iio <linux-iio@vger.kernel.org>, Greg KH <greg@kroah.com>
+Message-ID: <4BA76219.4030606@cam.ac.uk>
+
+
+Function iio_get_new_idr_val() return negative value if fails.
+So, only error when ret < 0 in iio_device_register_eventset().
+
+Signed-off-by: Sonic Zhang <sonic.adi@gmail.com>
+Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/iio/industrialio-core.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/staging/iio/industrialio-core.c
++++ b/drivers/staging/iio/industrialio-core.c
+@@ -537,6 +537,7 @@ static void iio_device_unregister_sysfs(
+ sysfs_remove_group(&dev_info->dev.kobj, dev_info->attrs);
+ }
+
++/* This function return negative value if fails. */
+ int iio_get_new_idr_val(struct idr *this_idr)
+ {
+ int ret;
+@@ -660,7 +661,7 @@ static int iio_device_register_eventset(
+ for (i = 0; i < dev_info->num_interrupt_lines; i++) {
+ dev_info->event_interfaces[i].owner = dev_info->driver_module;
+ ret = iio_get_new_idr_val(&iio_event_idr);
+- if (ret)
++ if (ret < 0)
+ goto error_free_setup_ev_ints;
+ else
+ dev_info->event_interfaces[i].id = ret;
diff --git a/staging/staging-iio-light-fix-dangling-pointers.patch b/staging/staging-iio-light-fix-dangling-pointers.patch
new file mode 100644
index 00000000000000..6b4eddedc1e81c
--- /dev/null
+++ b/staging/staging-iio-light-fix-dangling-pointers.patch
@@ -0,0 +1,39 @@
+From w.sang@pengutronix.de Thu Apr 22 16:39:09 2010
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Sat, 20 Mar 2010 15:13:03 +0100
+Subject: Staging: iio: light: fix dangling pointers
+To: kernel-janitors@vger.kernel.org
+Cc: devel@driverdev.osuosl.org, Wolfram Sang <w.sang@pengutronix.de>, Greg Kroah-Hartman <gregkh@suse.de>, linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org
+Message-ID: <1269094385-16114-23-git-send-email-w.sang@pengutronix.de>
+
+
+Fix I2C-drivers which missed setting clientdata to NULL before freeing the
+structure it points to. Also fix drivers which do this _after_ the structure
+was freed already.
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/iio/light/tsl2563.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/staging/iio/light/tsl2563.c
++++ b/drivers/staging/iio/light/tsl2563.c
+@@ -682,6 +682,7 @@ static int __devinit tsl2563_probe(struc
+ fail2:
+ iio_device_unregister(chip->indio_dev);
+ fail1:
++ i2c_set_clientdata(client, NULL);
+ kfree(chip);
+ return err;
+ }
+@@ -692,6 +693,7 @@ static int tsl2563_remove(struct i2c_cli
+
+ iio_device_unregister(chip->indio_dev);
+
++ i2c_set_clientdata(client, NULL);
+ kfree(chip);
+ return 0;
+ }
diff --git a/staging/staging-iio-lis3l02dq-incorrect-ws-used-in-container-of-call.patch b/staging/staging-iio-lis3l02dq-incorrect-ws-used-in-container-of-call.patch
new file mode 100644
index 00000000000000..69acd0e532fe14
--- /dev/null
+++ b/staging/staging-iio-lis3l02dq-incorrect-ws-used-in-container-of-call.patch
@@ -0,0 +1,33 @@
+From jic23@cam.ac.uk Thu Apr 22 16:37:59 2010
+From: Jonathan Cameron <jic23@cam.ac.uk>
+Date: Thu, 11 Mar 2010 17:29:48 +0000
+Subject: staging: iio: lis3l02dq - incorrect ws used in container of call.
+To: Greg KH <greg@kroah.com>, "linux-iio@vger.kernel.org" <linux-iio@vger.kernel.org>
+Message-ID: <4B99288C.3080601@cam.ac.uk>
+
+The word oops comes to mind. Original patch to merge the two work queues
+in here (prior to Greg taking them into staging) changed the top half to
+only use one of them and the bottom half to assume it was the other.
+
+Currently causes a NULL pointer dereference if you enable any of the events
+on an lis3l02dq. Just goes to show I need a few more regression tests.
+
+
+Signed-of-by: Jonathan Cameron <jic23@cam.ac.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/iio/accel/lis3l02dq_core.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/iio/accel/lis3l02dq_core.c
++++ b/drivers/staging/iio/accel/lis3l02dq_core.c
+@@ -618,7 +618,7 @@ static int lis3l02dq_thresh_handler_th(s
+ static void lis3l02dq_thresh_handler_bh_no_check(struct work_struct *work_s)
+ {
+ struct iio_work_cont *wc
+- = container_of(work_s, struct iio_work_cont, ws_nocheck);
++ = container_of(work_s, struct iio_work_cont, ws);
+ struct lis3l02dq_state *st = wc->st;
+ u8 t;
+
diff --git a/staging/staging-iio-ring_sw-fix-incorrect-test-on-successful-read-of-last-value-causes-infinite-loop.patch b/staging/staging-iio-ring_sw-fix-incorrect-test-on-successful-read-of-last-value-causes-infinite-loop.patch
new file mode 100644
index 00000000000000..b8d5fec4bbb79f
--- /dev/null
+++ b/staging/staging-iio-ring_sw-fix-incorrect-test-on-successful-read-of-last-value-causes-infinite-loop.patch
@@ -0,0 +1,31 @@
+From jic23@cam.ac.uk Thu Apr 22 16:41:09 2010
+From: Jonathan Cameron <jic23@cam.ac.uk>
+Date: Tue, 30 Mar 2010 17:45:04 +0100
+Subject: staging: iio: ring_sw: Fix incorrect test on successful read of last value, causes infinite loop
+To: "linux-iio@vger.kernel.org" <linux-iio@vger.kernel.org>, Greg Kroah-Hartman <gregkh@suse.de>
+Message-ID: <4BB22A90.6070801@cam.ac.uk>
+
+
+This is a bad one. The test means that almost no reads of the last
+value ever succeed! Result is an infinite loop.
+
+Another one for the 'oops' category.
+
+Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/iio/ring_sw.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/iio/ring_sw.c
++++ b/drivers/staging/iio/ring_sw.c
+@@ -293,7 +293,7 @@ again:
+ return -EAGAIN;
+ memcpy(data, last_written_p_copy, ring->buf.bpd);
+
+- if (unlikely(ring->last_written_p >= last_written_p_copy))
++ if (unlikely(ring->last_written_p != last_written_p_copy))
+ goto again;
+
+ iio_unmark_sw_rb_in_use(&ring->buf);
diff --git a/staging/staging-iio-test-for-failed-allocation.patch b/staging/staging-iio-test-for-failed-allocation.patch
new file mode 100644
index 00000000000000..e9828c0f9c7e43
--- /dev/null
+++ b/staging/staging-iio-test-for-failed-allocation.patch
@@ -0,0 +1,32 @@
+From error27@gmail.com Thu Apr 22 16:38:42 2010
+From: Dan Carpenter <error27@gmail.com>
+Date: Tue, 16 Mar 2010 13:03:49 +0300
+Subject: Staging: iio: test for failed allocation
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: devel@driverdev.osuosl.org, kernel-janitors@vger.kernel.org, Jonathan Cameron <jic23@cam.ac.uk>, linux-kernel@vger.kernel.org
+Message-ID: <20100316100349.GA4219@bicker>
+Content-Disposition: inline
+
+
+We should return test to see if iio_allocate_trigger() fails and return -ENOMEM.
+
+Signed-off-by: Dan Carpenter <error27@gmail.com>
+Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/iio/accel/lis3l02dq_ring.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
++++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
+@@ -493,6 +493,9 @@ int lis3l02dq_probe_trigger(struct iio_d
+ struct lis3l02dq_state *state = indio_dev->dev_data;
+
+ state->trig = iio_allocate_trigger();
++ if (!state->trig)
++ return -ENOMEM;
++
+ state->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL);
+ if (!state->trig->name) {
+ ret = -ENOMEM;
diff --git a/staging/staging-intel-restricted-access-region-handler.patch b/staging/staging-intel-restricted-access-region-handler.patch
new file mode 100644
index 00000000000000..2f2e40c740e90c
--- /dev/null
+++ b/staging/staging-intel-restricted-access-region-handler.patch
@@ -0,0 +1,1821 @@
+From ossama.othman@intel.com Thu Apr 22 17:01:24 2010
+From: Ossama Othman <ossama.othman@intel.com>
+Date: Mon, 15 Mar 2010 16:23:56 -0700
+Subject: staging: Intel Restricted Access Region Handler
+To: Greg Kroah-Hartman <gregkh@suse.de>, linux-kernel@vger.kernel.org
+Cc: Ossama Othman <ossama.othman@intel.com>
+Message-ID: <1268695436-22203-1-git-send-email-ossama.othman@intel.com>
+
+
+The Intel Restricted Access Region Handler provides a buffer allocation
+mechanism to RAR users. Since the intended usage model is to lock out
+CPU access to RAR (the CPU will not be able to access RAR memory), this
+driver does not access RAR memory, and merely keeps track of what areas
+of RAR memory are in use. It has it's own simple allocator that does
+not rely on existing kernel allocators (SLAB, etc) since those
+allocators are too tightly coupled with the paging mechanism, which isn't
+needed for the intended RAR use cases.
+
+An mmap() implementation is provided for debugging purposes to simplify
+RAR memory access from the user space. However, it will effectively be
+a no-op when RAR access control is enabled since the CPU will not be
+able to access RAR.
+
+This driver should not be confused with the rar_register driver. That
+driver exposes an interface to access RAR registers on the Moorestown
+platform. The RAR handler driver relies on the rar_register driver for
+low level RAR register reads and writes.
+
+This patch was generated and built against the latest linux-2.6 master
+branch.
+
+Signed-off-by: Ossama Othman <ossama.othman@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/Kconfig | 2
+ drivers/staging/Makefile | 1
+ drivers/staging/memrar/Kconfig | 15
+ drivers/staging/memrar/Makefile | 2
+ drivers/staging/memrar/TODO | 43 +
+ drivers/staging/memrar/memrar.h | 155 ++++
+ drivers/staging/memrar/memrar_allocator.c | 432 +++++++++++++
+ drivers/staging/memrar/memrar_allocator.h | 149 ++++
+ drivers/staging/memrar/memrar_handler.c | 937 ++++++++++++++++++++++++++++++
+ 9 files changed, 1736 insertions(+)
+
+--- a/drivers/staging/Kconfig
++++ b/drivers/staging/Kconfig
+@@ -111,6 +111,8 @@ source "drivers/staging/vme/Kconfig"
+
+ source "drivers/staging/rar_register/Kconfig"
+
++source "drivers/staging/memrar/Kconfig"
++
+ source "drivers/staging/sep/Kconfig"
+
+ source "drivers/staging/iio/Kconfig"
+--- a/drivers/staging/Makefile
++++ b/drivers/staging/Makefile
+@@ -36,6 +36,7 @@ obj-$(CONFIG_FB_UDL) += udlfb/
+ obj-$(CONFIG_HYPERV) += hv/
+ obj-$(CONFIG_VME_BUS) += vme/
+ obj-$(CONFIG_RAR_REGISTER) += rar_register/
++obj-$(CONFIG_MRST_RAR_HANDLER) += memrar/
+ obj-$(CONFIG_DX_SEP) += sep/
+ obj-$(CONFIG_IIO) += iio/
+ obj-$(CONFIG_RAMZSWAP) += ramzswap/
+--- /dev/null
++++ b/drivers/staging/memrar/Kconfig
+@@ -0,0 +1,15 @@
++config MRST_RAR_HANDLER
++ tristate "RAR handler driver for Intel Moorestown platform"
++ select RAR_REGISTER
++ ---help---
++ This driver provides a memory management interface to
++ restricted access regions (RAR) available on the Intel
++ Moorestown platform.
++
++ Once locked down, restricted access regions are only
++ accessible by specific hardware on the platform. The x86
++ CPU is typically not one of those platforms. As such this
++ driver does not access RAR, and only provides a buffer
++ allocation/bookkeeping mechanism.
++
++ If unsure, say N.
+--- /dev/null
++++ b/drivers/staging/memrar/Makefile
+@@ -0,0 +1,2 @@
++obj-$(CONFIG_MRST_RAR_HANDLER) += memrar.o
++memrar-y := memrar_allocator.o memrar_handler.o
+--- /dev/null
++++ b/drivers/staging/memrar/TODO
+@@ -0,0 +1,43 @@
++RAR Handler (memrar) Driver TODO Items
++======================================
++
++Maintainer: Ossama Othman <ossama.othman@intel.com>
++
++memrar.h
++--------
++1. This header exposes the driver's user space and kernel space
++ interfaces. It should be moved to <linux/rar/memrar.h>, or
++ something along those lines, when this memrar driver is moved out
++ of `staging'.
++ a. It would be ideal if staging/rar_register/rar_register.h was
++ moved to the same directory.
++
++memrar_allocator.[ch]
++---------------------
++1. Address potential fragmentation issues with the memrar_allocator.
++
++2. Hide struct memrar_allocator details/fields. They need not be
++ exposed to the user.
++ a. Forward declare struct memrar_allocator.
++ b. Move all three struct definitions to `memrar_allocator.c'
++ source file.
++ c. Add a memrar_allocator_largest_free_area() function, or
++ something like that to get access to the value of the struct
++ memrar_allocator "largest_free_area" field. This allows the
++ struct memrar_allocator fields to be completely hidden from
++ the user. The memrar_handler code really only needs this for
++ statistic gathering on-demand.
++ d. Do the same for the "capacity" field as the
++ "largest_free_area" field.
++
++3. Move memrar_allocator.* to kernel `lib' directory since it is HW
++ neutral.
++ a. Alternatively, use lib/genalloc.c instead.
++ b. A kernel port of Doug Lea's malloc() implementation may also
++ be an option.
++
++memrar_handler.c
++----------------
++1. Split user space interface (ioctl code) from core/kernel code,
++ e.g.:
++ memrar_handler.c -> memrar_core.c, memrar_user.c
+--- /dev/null
++++ b/drivers/staging/memrar/memrar.h
+@@ -0,0 +1,155 @@
++/*
++ * RAR Handler (/dev/memrar) internal driver API.
++ * Copyright (C) 2010 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General
++ * Public License as published by the Free Software Foundation.
++ *
++ * 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., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ * The full GNU General Public License is included in this
++ * distribution in the file called COPYING.
++ */
++
++
++#ifndef _MEMRAR_H
++#define _MEMRAR_H
++
++#include <linux/ioctl.h>
++#include <linux/types.h>
++
++
++/**
++ * struct RAR_stat - RAR statistics structure
++ * @type: Type of RAR memory (e.g., audio vs. video)
++ * @capacity: Total size of RAR memory region.
++ * @largest_block_size: Size of the largest reservable block.
++ *
++ * This structure is used for RAR_HANDLER_STAT ioctl and for the
++ * RAR_get_stat() user space wrapper function.
++ */
++struct RAR_stat {
++ __u32 type;
++ __u32 capacity;
++ __u32 largest_block_size;
++};
++
++
++/**
++ * struct RAR_block_info - user space struct that describes RAR buffer
++ * @type: Type of RAR memory (e.g., audio vs. video)
++ * @size: Requested size of a block to be reserved in RAR.
++ * @handle: Handle that can be used to refer to reserved block.
++ *
++ * This is the basic structure exposed to the user space that
++ * describes a given RAR buffer. The buffer's underlying bus address
++ * is not exposed to the user. User space code refers to the buffer
++ * entirely by "handle".
++ */
++struct RAR_block_info {
++ __u32 type;
++ __u32 size;
++ __u32 handle;
++};
++
++
++#define RAR_IOCTL_BASE 0xE0
++
++/* Reserve RAR block. */
++#define RAR_HANDLER_RESERVE _IOWR(RAR_IOCTL_BASE, 0x00, struct RAR_block_info)
++
++/* Release previously reserved RAR block. */
++#define RAR_HANDLER_RELEASE _IOW(RAR_IOCTL_BASE, 0x01, __u32)
++
++/* Get RAR stats. */
++#define RAR_HANDLER_STAT _IOWR(RAR_IOCTL_BASE, 0x02, struct RAR_stat)
++
++
++#ifdef __KERNEL__
++
++/* -------------------------------------------------------------- */
++/* Kernel Side RAR Handler Interface */
++/* -------------------------------------------------------------- */
++
++/**
++ * struct RAR_buffer - kernel space struct that describes RAR buffer
++ * @info: structure containing base RAR buffer information
++ * @bus_address: buffer bus address
++ *
++ * Structure that contains all information related to a given block of
++ * memory in RAR. It is generally only used when retrieving RAR
++ * related bus addresses.
++ *
++ * Note: This structure is used only by RAR-enabled drivers, and is
++ * not intended to be exposed to the user space.
++ */
++struct RAR_buffer {
++ struct RAR_block_info info;
++ dma_addr_t bus_address;
++};
++
++/**
++ * rar_reserve() - reserve RAR buffers
++ * @buffers: array of RAR_buffers where type and size of buffers to
++ * reserve are passed in, handle and bus address are
++ * passed out
++ * @count: number of RAR_buffers in the "buffers" array
++ *
++ * This function will reserve buffers in the restricted access regions
++ * of given types.
++ *
++ * It returns the number of successfully reserved buffers. Successful
++ * buffer reservations will have the corresponding bus_address field
++ * set to a non-zero value in the given buffers vector.
++ */
++extern size_t rar_reserve(struct RAR_buffer *buffers,
++ size_t count);
++
++/**
++ * rar_release() - release RAR buffers
++ * @buffers: array of RAR_buffers where handles to buffers to be
++ * released are passed in
++ * @count: number of RAR_buffers in the "buffers" array
++ *
++ * This function will release RAR buffers that were retrieved through
++ * a call to rar_reserve() or rar_handle_to_bus() by decrementing the
++ * reference count. The RAR buffer will be reclaimed when the
++ * reference count drops to zero.
++ *
++ * It returns the number of successfully released buffers. Successful
++ * releases will have their handle field set to zero in the given
++ * buffers vector.
++ */
++extern size_t rar_release(struct RAR_buffer *buffers,
++ size_t count);
++
++/**
++ * rar_handle_to_bus() - convert a vector of RAR handles to bus addresses
++ * @buffers: array of RAR_buffers containing handles to be
++ * converted to bus_addresses
++ * @count: number of RAR_buffers in the "buffers" array
++
++ * This function will retrieve the RAR buffer bus addresses, type and
++ * size corresponding to the RAR handles provided in the buffers
++ * vector.
++ *
++ * It returns the number of successfully converted buffers. The bus
++ * address will be set to 0 for unrecognized handles.
++ *
++ * The reference count for each corresponding buffer in RAR will be
++ * incremented. Call rar_release() when done with the buffers.
++ */
++extern size_t rar_handle_to_bus(struct RAR_buffer *buffers,
++ size_t count);
++
++
++#endif /* __KERNEL__ */
++
++#endif /* _MEMRAR_H */
+--- /dev/null
++++ b/drivers/staging/memrar/memrar_allocator.c
+@@ -0,0 +1,432 @@
++/*
++ * memrar_allocator 1.0: An allocator for Intel RAR.
++ *
++ * Copyright (C) 2010 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General
++ * Public License as published by the Free Software Foundation.
++ *
++ * 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., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ * The full GNU General Public License is included in this
++ * distribution in the file called COPYING.
++ *
++ *
++ * ------------------------------------------------------------------
++ *
++ * This simple allocator implementation provides a
++ * malloc()/free()-like interface for reserving space within a
++ * previously reserved block of memory. It is not specific to
++ * any hardware, nor is it coupled with the lower level paging
++ * mechanism.
++ *
++ * The primary goal of this implementation is to provide a means
++ * to partition an arbitrary block of memory without actually
++ * accessing the memory or incurring any hardware side-effects
++ * (e.g. paging). It is, in effect, a bookkeeping mechanism for
++ * buffers.
++ */
++
++
++#include "memrar_allocator.h"
++#include <linux/slab.h>
++#include <linux/bug.h>
++#include <linux/kernel.h>
++
++
++struct memrar_allocator *memrar_create_allocator(unsigned long base,
++ size_t capacity,
++ size_t block_size)
++{
++ struct memrar_allocator *allocator = NULL;
++ struct memrar_address_ranges *first_node = NULL;
++
++ /*
++ * Make sure the base address is aligned on a block_size
++ * boundary.
++ *
++ * @todo Is this necessary?
++ */
++ /* base = ALIGN(base, block_size); */
++
++ /* Validate parameters.
++ *
++ * Make sure we can allocate the entire memory space. Zero
++ * capacity or block size are obviously invalid.
++ */
++ if (base == 0
++ || capacity == 0
++ || block_size == 0
++ || ULONG_MAX - capacity < base
++ || capacity < block_size)
++ return allocator;
++
++ /*
++ * There isn't much point in creating a memory allocator that
++ * is only capable of holding one block but we'll allow it,
++ * and issue a diagnostic.
++ */
++ WARN(capacity < block_size * 2,
++ "memrar: Only one block available to allocator.\n");
++
++ allocator = kmalloc(sizeof(*allocator), GFP_KERNEL);
++
++ if (allocator == NULL)
++ return allocator;
++
++ mutex_init(&allocator->lock);
++ allocator->base = base;
++
++ /* Round the capacity down to a multiple of block_size. */
++ allocator->capacity = (capacity / block_size) * block_size;
++
++ allocator->block_size = block_size;
++
++ allocator->largest_free_area = allocator->capacity;
++
++ /* Initialize the handle and free lists. */
++ INIT_LIST_HEAD(&allocator->allocated_list.list);
++ INIT_LIST_HEAD(&allocator->free_list.list);
++
++ first_node = kmalloc(sizeof(*first_node), GFP_KERNEL);
++ if (first_node == NULL) {
++ kfree(allocator);
++ allocator = NULL;
++ } else {
++ /* Full range of blocks is available. */
++ first_node->range.begin = base;
++ first_node->range.end = base + allocator->capacity;
++ list_add(&first_node->list,
++ &allocator->free_list.list);
++ }
++
++ return allocator;
++}
++
++void memrar_destroy_allocator(struct memrar_allocator *allocator)
++{
++ /*
++ * Assume that the memory allocator lock isn't held at this
++ * point in time. Caller must ensure that.
++ */
++
++ struct memrar_address_ranges *pos = NULL;
++ struct memrar_address_ranges *n = NULL;
++
++ if (allocator == NULL)
++ return;
++
++ mutex_lock(&allocator->lock);
++
++ /* Reclaim free list resources. */
++ list_for_each_entry_safe(pos,
++ n,
++ &allocator->free_list.list,
++ list) {
++ list_del(&pos->list);
++ kfree(pos);
++ }
++
++ mutex_unlock(&allocator->lock);
++
++ kfree(allocator);
++}
++
++unsigned long memrar_allocator_alloc(struct memrar_allocator *allocator,
++ size_t size)
++{
++ struct memrar_address_ranges *pos = NULL;
++
++ size_t num_blocks;
++ unsigned long reserved_bytes;
++
++ /*
++ * Address of allocated buffer. We assume that zero is not a
++ * valid address.
++ */
++ unsigned long addr = 0;
++
++ if (allocator == NULL || size == 0)
++ return addr;
++
++ /* Reserve enough blocks to hold the amount of bytes requested. */
++ num_blocks = DIV_ROUND_UP(size, allocator->block_size);
++
++ reserved_bytes = num_blocks * allocator->block_size;
++
++ mutex_lock(&allocator->lock);
++
++ if (reserved_bytes > allocator->largest_free_area) {
++ mutex_unlock(&allocator->lock);
++ return addr;
++ }
++
++ /*
++ * Iterate through the free list to find a suitably sized
++ * range of free contiguous memory blocks.
++ *
++ * We also take the opportunity to reset the size of the
++ * largest free area size statistic.
++ */
++ list_for_each_entry(pos, &allocator->free_list.list, list) {
++ struct memrar_address_range * const fr = &pos->range;
++ size_t const curr_size = fr->end - fr->begin;
++
++ if (curr_size >= reserved_bytes && addr == 0) {
++ struct memrar_address_range *range = NULL;
++ struct memrar_address_ranges * const new_node =
++ kmalloc(sizeof(*new_node), GFP_KERNEL);
++
++ if (new_node == NULL)
++ break;
++
++ list_add(&new_node->list,
++ &allocator->allocated_list.list);
++
++ /*
++ * Carve out area of memory from end of free
++ * range.
++ */
++ range = &new_node->range;
++ range->end = fr->end;
++ fr->end -= reserved_bytes;
++ range->begin = fr->end;
++ addr = range->begin;
++
++ /*
++ * Check if largest area has decreased in
++ * size. We'll need to continue scanning for
++ * the next largest area if it has.
++ */
++ if (curr_size == allocator->largest_free_area)
++ allocator->largest_free_area -=
++ reserved_bytes;
++ else
++ break;
++ }
++
++ /*
++ * Reset largest free area size statistic as needed,
++ * but only if we've actually allocated memory.
++ */
++ if (addr != 0
++ && curr_size > allocator->largest_free_area) {
++ allocator->largest_free_area = curr_size;
++ break;
++ }
++ }
++
++ mutex_unlock(&allocator->lock);
++
++ return addr;
++}
++
++long memrar_allocator_free(struct memrar_allocator *allocator,
++ unsigned long addr)
++{
++ struct list_head *pos = NULL;
++ struct list_head *tmp = NULL;
++ struct list_head *dst = NULL;
++
++ struct memrar_address_ranges *allocated = NULL;
++ struct memrar_address_range const *handle = NULL;
++
++ unsigned long old_end = 0;
++ unsigned long new_chunk_size = 0;
++
++ if (allocator == NULL)
++ return -EINVAL;
++
++ if (addr == 0)
++ return 0; /* Ignore "free(0)". */
++
++ mutex_lock(&allocator->lock);
++
++ /* Find the corresponding handle. */
++ list_for_each_entry(allocated,
++ &allocator->allocated_list.list,
++ list) {
++ if (allocated->range.begin == addr) {
++ handle = &allocated->range;
++ break;
++ }
++ }
++
++ /* No such buffer created by this allocator. */
++ if (handle == NULL) {
++ mutex_unlock(&allocator->lock);
++ return -EFAULT;
++ }
++
++ /*
++ * Coalesce adjacent chunks of memory if possible.
++ *
++ * @note This isn't full blown coalescing since we're only
++ * coalescing at most three chunks of memory.
++ */
++ list_for_each_safe(pos, tmp, &allocator->free_list.list) {
++ /* @todo O(n) performance. Optimize. */
++
++ struct memrar_address_range * const chunk =
++ &list_entry(pos,
++ struct memrar_address_ranges,
++ list)->range;
++
++ /* Extend size of existing free adjacent chunk. */
++ if (chunk->end == handle->begin) {
++ /*
++ * Chunk "less than" than the one we're
++ * freeing is adjacent.
++ *
++ * Before:
++ *
++ * +-----+------+
++ * |chunk|handle|
++ * +-----+------+
++ *
++ * After:
++ *
++ * +------------+
++ * | chunk |
++ * +------------+
++ */
++
++ struct memrar_address_ranges const * const next =
++ list_entry(pos->next,
++ struct memrar_address_ranges,
++ list);
++
++ chunk->end = handle->end;
++
++ /*
++ * Now check if next free chunk is adjacent to
++ * the current extended free chunk.
++ *
++ * Before:
++ *
++ * +------------+----+
++ * | chunk |next|
++ * +------------+----+
++ *
++ * After:
++ *
++ * +-----------------+
++ * | chunk |
++ * +-----------------+
++ */
++ if (!list_is_singular(pos)
++ && chunk->end == next->range.begin) {
++ chunk->end = next->range.end;
++ list_del(pos->next);
++ kfree(next);
++ }
++
++ list_del(&allocated->list);
++
++ new_chunk_size = chunk->end - chunk->begin;
++
++ goto exit_memrar_free;
++
++ } else if (handle->end == chunk->begin) {
++ /*
++ * Chunk "greater than" than the one we're
++ * freeing is adjacent.
++ *
++ * +------+-----+
++ * |handle|chunk|
++ * +------+-----+
++ *
++ * After:
++ *
++ * +------------+
++ * | chunk |
++ * +------------+
++ */
++
++ struct memrar_address_ranges const * const prev =
++ list_entry(pos->prev,
++ struct memrar_address_ranges,
++ list);
++
++ chunk->begin = handle->begin;
++
++ /*
++ * Now check if previous free chunk is
++ * adjacent to the current extended free
++ * chunk.
++ *
++ *
++ * Before:
++ *
++ * +----+------------+
++ * |prev| chunk |
++ * +----+------------+
++ *
++ * After:
++ *
++ * +-----------------+
++ * | chunk |
++ * +-----------------+
++ */
++ if (!list_is_singular(pos)
++ && prev->range.end == chunk->begin) {
++ chunk->begin = prev->range.begin;
++ list_del(pos->prev);
++ kfree(prev);
++ }
++
++ list_del(&allocated->list);
++
++ new_chunk_size = chunk->end - chunk->begin;
++
++ goto exit_memrar_free;
++
++ } else if (chunk->end < handle->begin
++ && chunk->end > old_end) {
++ /* Keep track of where the entry could be
++ * potentially moved from the "allocated" list
++ * to the "free" list if coalescing doesn't
++ * occur, making sure the "free" list remains
++ * sorted.
++ */
++ old_end = chunk->end;
++ dst = pos;
++ }
++ }
++
++ /*
++ * Nothing to coalesce.
++ *
++ * Move the entry from the "allocated" list to the "free"
++ * list.
++ */
++ list_move(&allocated->list, dst);
++ new_chunk_size = handle->end - handle->begin;
++ allocated = NULL;
++
++exit_memrar_free:
++
++ if (new_chunk_size > allocator->largest_free_area)
++ allocator->largest_free_area = new_chunk_size;
++
++ mutex_unlock(&allocator->lock);
++
++ kfree(allocated);
++
++ return 0;
++}
++
++
++
++/*
++ Local Variables:
++ c-file-style: "linux"
++ End:
++*/
+--- /dev/null
++++ b/drivers/staging/memrar/memrar_allocator.h
+@@ -0,0 +1,149 @@
++/*
++ * Copyright (C) 2010 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General
++ * Public License as published by the Free Software Foundation.
++ *
++ * 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., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ * The full GNU General Public License is included in this
++ * distribution in the file called COPYING.
++ */
++
++#ifndef MEMRAR_ALLOCATOR_H
++#define MEMRAR_ALLOCATOR_H
++
++
++#include <linux/mutex.h>
++#include <linux/list.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++
++
++/**
++ * struct memrar_address_range - struct that describes a memory range
++ * @begin: Beginning of available address range.
++ * @end: End of available address range, one past the end,
++ * i.e. [begin, end).
++ */
++struct memrar_address_range {
++/* private: internal use only */
++ unsigned long begin;
++ unsigned long end;
++};
++
++/**
++ * struct memrar_address_ranges - list of areas of memory.
++ * @list: Linked list of address ranges.
++ * @range: Memory address range corresponding to given list node.
++ */
++struct memrar_address_ranges {
++/* private: internal use only */
++ struct list_head list;
++ struct memrar_address_range range;
++};
++
++/**
++ * struct memrar_allocator - encapsulation of the memory allocator state
++ * @lock: Lock used to synchronize access to the memory
++ * allocator state.
++ * @base: Base (start) address of the allocator memory
++ * space.
++ * @capacity: Size of the allocator memory space in bytes.
++ * @block_size: The size in bytes of individual blocks within
++ * the allocator memory space.
++ * @largest_free_area: Largest free area of memory in the allocator
++ * in bytes.
++ * @allocated_list: List of allocated memory block address
++ * ranges.
++ * @free_list: List of free address ranges.
++ *
++ * This structure contains all memory allocator state, including the
++ * base address, capacity, free list, lock, etc.
++ */
++struct memrar_allocator {
++/* private: internal use only */
++ struct mutex lock;
++ unsigned long base;
++ size_t capacity;
++ size_t block_size;
++ size_t largest_free_area;
++ struct memrar_address_ranges allocated_list;
++ struct memrar_address_ranges free_list;
++};
++
++/**
++ * memrar_create_allocator() - create a memory allocator
++ * @base: Address at which the memory allocator begins.
++ * @capacity: Desired size of the memory allocator. This value must
++ * be larger than the block_size, ideally more than twice
++ * as large since there wouldn't be much point in using a
++ * memory allocator otherwise.
++ * @block_size: The size of individual blocks within the memory
++ * allocator. This value must smaller than the
++ * capacity.
++ *
++ * Create a memory allocator with the given capacity and block size.
++ * The capacity will be reduced to be a multiple of the block size, if
++ * necessary.
++ *
++ * Returns an instance of the memory allocator, if creation succeeds,
++ * otherwise zero if creation fails. Failure may occur if not enough
++ * kernel memory exists to create the memrar_allocator instance
++ * itself, or if the capacity and block_size arguments are not
++ * compatible or make sense.
++ */
++struct memrar_allocator *memrar_create_allocator(unsigned long base,
++ size_t capacity,
++ size_t block_size);
++
++/**
++ * memrar_destroy_allocator() - destroy allocator
++ * @allocator: The allocator being destroyed.
++ *
++ * Reclaim resources held by the memory allocator. The caller must
++ * explicitly free all memory reserved by memrar_allocator_alloc()
++ * prior to calling this function. Otherwise leaks will occur.
++ */
++void memrar_destroy_allocator(struct memrar_allocator *allocator);
++
++/**
++ * memrar_allocator_alloc() - reserve an area of memory of given size
++ * @allocator: The allocator instance being used to reserve buffer.
++ * @size: The size in bytes of the buffer to allocate.
++ *
++ * This functions reserves an area of memory managed by the given
++ * allocator. It returns zero if allocation was not possible.
++ * Failure may occur if the allocator no longer has space available.
++ */
++unsigned long memrar_allocator_alloc(struct memrar_allocator *allocator,
++ size_t size);
++
++/**
++ * memrar_allocator_free() - release buffer starting at given address
++ * @allocator: The allocator instance being used to release the buffer.
++ * @address: The address of the buffer being released.
++ *
++ * Release an area of memory starting at the given address. Failure
++ * could occur if the given address is not in the address space
++ * managed by the allocator. Returns zero on success or an errno
++ * (negative value) on failure.
++ */
++long memrar_allocator_free(struct memrar_allocator *allocator,
++ unsigned long address);
++
++#endif /* MEMRAR_ALLOCATOR_H */
++
++
++/*
++ Local Variables:
++ c-file-style: "linux"
++ End:
++*/
+--- /dev/null
++++ b/drivers/staging/memrar/memrar_handler.c
+@@ -0,0 +1,937 @@
++/*
++ * memrar_handler 1.0: An Intel restricted access region handler device
++ *
++ * Copyright (C) 2010 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General
++ * Public License as published by the Free Software Foundation.
++ *
++ * 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., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ * The full GNU General Public License is included in this
++ * distribution in the file called COPYING.
++ *
++ * -------------------------------------------------------------------
++ *
++ * Moorestown restricted access regions (RAR) provide isolated
++ * areas of main memory that are only acceessible by authorized
++ * devices.
++ *
++ * The Intel Moorestown RAR handler module exposes a kernel space
++ * RAR memory management mechanism. It is essentially a
++ * RAR-specific allocator.
++ *
++ * Besides providing RAR buffer management, the RAR handler also
++ * behaves in many ways like an OS virtual memory manager. For
++ * example, the RAR "handles" created by the RAR handler are
++ * analogous to user space virtual addresses.
++ *
++ * RAR memory itself is never accessed directly by the RAR
++ * handler.
++ */
++
++#include <linux/miscdevice.h>
++#include <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/kref.h>
++#include <linux/mutex.h>
++#include <linux/kernel.h>
++#include <linux/uaccess.h>
++#include <linux/mm.h>
++#include <linux/ioport.h>
++#include <linux/io.h>
++
++#include "../rar_register/rar_register.h"
++
++#include "memrar.h"
++#include "memrar_allocator.h"
++
++
++#define MEMRAR_VER "1.0"
++
++/*
++ * Moorestown supports three restricted access regions.
++ *
++ * We only care about the first two, video and audio. The third,
++ * reserved for Chaabi and the P-unit, will be handled by their
++ * respective drivers.
++ */
++#define MRST_NUM_RAR 2
++
++/* ---------------- -------------------- ------------------- */
++
++/**
++ * struct memrar_buffer_info - struct that keeps track of all RAR buffers
++ * @list: Linked list of memrar_buffer_info objects.
++ * @buffer: Core RAR buffer information.
++ * @refcount: Reference count.
++ * @owner: File handle corresponding to process that reserved the
++ * block of memory in RAR. This will be zero for buffers
++ * allocated by other drivers instead of by a user space
++ * process.
++ *
++ * This structure encapsulates a link list of RAR buffers, as well as
++ * other characteristics specific to a given list node, such as the
++ * reference count on the corresponding RAR buffer.
++ */
++struct memrar_buffer_info {
++ struct list_head list;
++ struct RAR_buffer buffer;
++ struct kref refcount;
++ struct file *owner;
++};
++
++/**
++ * struct memrar_rar_info - characteristics of a given RAR
++ * @base: Base bus address of the RAR.
++ * @length: Length of the RAR.
++ * @iobase: Virtual address of RAR mapped into kernel.
++ * @allocator: Allocator associated with the RAR. Note the allocator
++ * "capacity" may be smaller than the RAR length if the
++ * length is not a multiple of the configured allocator
++ * block size.
++ * @buffers: Table that keeps track of all reserved RAR buffers.
++ * @lock: Lock used to synchronize access to RAR-specific data
++ * structures.
++ *
++ * Each RAR has an associated memrar_rar_info structure that describes
++ * where in memory the RAR is located, how large it is, and a list of
++ * reserved RAR buffers inside that RAR. Each RAR also has a mutex
++ * associated with it to reduce lock contention when operations on
++ * multiple RARs are performed in parallel.
++ */
++struct memrar_rar_info {
++ dma_addr_t base;
++ unsigned long length;
++ void __iomem *iobase;
++ struct memrar_allocator *allocator;
++ struct memrar_buffer_info buffers;
++ struct mutex lock;
++};
++
++/*
++ * Array of RAR characteristics.
++ */
++static struct memrar_rar_info memrars[MRST_NUM_RAR];
++
++/* ---------------- -------------------- ------------------- */
++
++/* Validate RAR type. */
++static inline int memrar_is_valid_rar_type(u32 type)
++{
++ return type == RAR_TYPE_VIDEO || type == RAR_TYPE_AUDIO;
++}
++
++/* Check if an address/handle falls with the given RAR memory range. */
++static inline int memrar_handle_in_range(struct memrar_rar_info *rar,
++ u32 vaddr)
++{
++ unsigned long const iobase = (unsigned long) (rar->iobase);
++ return (vaddr >= iobase && vaddr < iobase + rar->length);
++}
++
++/* Retrieve RAR information associated with the given handle. */
++static struct memrar_rar_info *memrar_get_rar_info(u32 vaddr)
++{
++ int i;
++ for (i = 0; i < MRST_NUM_RAR; ++i) {
++ struct memrar_rar_info * const rar = &memrars[i];
++ if (memrar_handle_in_range(rar, vaddr))
++ return rar;
++ }
++
++ return NULL;
++}
++
++/*
++ * Retrieve bus address from given handle.
++ *
++ * Returns address corresponding to given handle. Zero if handle is
++ * invalid.
++ */
++static dma_addr_t memrar_get_bus_address(
++ struct memrar_rar_info *rar,
++ u32 vaddr)
++{
++ unsigned long const iobase = (unsigned long) (rar->iobase);
++
++ if (!memrar_handle_in_range(rar, vaddr))
++ return 0;
++
++ /*
++ * An assumption is made that the virtual address offset is
++ * the same as the bus address offset, at least based on the
++ * way this driver is implemented. For example, vaddr + 2 ==
++ * baddr + 2.
++ *
++ * @todo Is that a valid assumption?
++ */
++ return rar->base + (vaddr - iobase);
++}
++
++/*
++ * Retrieve physical address from given handle.
++ *
++ * Returns address corresponding to given handle. Zero if handle is
++ * invalid.
++ */
++static dma_addr_t memrar_get_physical_address(
++ struct memrar_rar_info *rar,
++ u32 vaddr)
++{
++ /*
++ * @todo This assumes that the bus address and physical
++ * address are the same. That is true for Moorestown
++ * but not necessarily on other platforms. This
++ * deficiency should be addressed at some point.
++ */
++ return memrar_get_bus_address(rar, vaddr);
++}
++
++/*
++ * Core block release code.
++ *
++ * Note: This code removes the node from a list. Make sure any list
++ * iteration is performed using list_for_each_safe().
++ */
++static void memrar_release_block_i(struct kref *ref)
++{
++ /*
++ * Last reference is being released. Remove from the table,
++ * and reclaim resources.
++ */
++
++ struct memrar_buffer_info * const node =
++ container_of(ref, struct memrar_buffer_info, refcount);
++
++ struct RAR_block_info * const user_info =
++ &node->buffer.info;
++
++ struct memrar_allocator * const allocator =
++ memrars[user_info->type].allocator;
++
++ list_del(&node->list);
++
++ memrar_allocator_free(allocator, user_info->handle);
++
++ kfree(node);
++}
++
++/*
++ * Initialize RAR parameters, such as bus addresses, etc.
++ */
++static int memrar_init_rar_resources(char const *devname)
++{
++ /* ---- Sanity Checks ----
++ * 1. RAR bus addresses in both Lincroft and Langwell RAR
++ * registers should be the same.
++ * a. There's no way we can do this through IA.
++ *
++ * 2. Secure device ID in Langwell RAR registers should be set
++ * appropriately, e.g. only LPE DMA for the audio RAR, and
++ * security for the other Langwell based RAR registers.
++ * a. There's no way we can do this through IA.
++ *
++ * 3. Audio and video RAR registers and RAR access should be
++ * locked down. If not, enable RAR access control. Except
++ * for debugging purposes, there is no reason for them to
++ * be unlocked.
++ * a. We can only do this for the Lincroft (IA) side.
++ *
++ * @todo Should the RAR handler driver even be aware of audio
++ * and video RAR settings?
++ */
++
++ /*
++ * RAR buffer block size.
++ *
++ * We choose it to be the size of a page to simplify the
++ * /dev/memrar mmap() implementation and usage. Otherwise
++ * paging is not involved once an RAR is locked down.
++ */
++ static size_t const RAR_BLOCK_SIZE = PAGE_SIZE;
++
++ int z;
++ int found_rar = 0;
++
++ BUG_ON(MRST_NUM_RAR != ARRAY_SIZE(memrars));
++
++ for (z = 0; z != MRST_NUM_RAR; ++z) {
++ dma_addr_t low, high;
++ struct memrar_rar_info * const rar = &memrars[z];
++
++ BUG_ON(!memrar_is_valid_rar_type(z));
++
++ mutex_init(&rar->lock);
++
++ /*
++ * Initialize the process table before we reach any
++ * code that exit on failure since the finalization
++ * code requires an initialized list.
++ */
++ INIT_LIST_HEAD(&rar->buffers.list);
++
++ if (rar_get_address(z, &low, &high) != 0) {
++ /* No RAR is available. */
++ break;
++ } else if (low == 0 || high == 0) {
++ /*
++ * We don't immediately break out of the loop
++ * since the next type of RAR may be enabled.
++ */
++ rar->base = 0;
++ rar->length = 0;
++ rar->iobase = NULL;
++ rar->allocator = NULL;
++ continue;
++ }
++
++ /*
++ * @todo Verify that LNC and LNW RAR register contents
++ * addresses, security, etc are compatible and
++ * consistent).
++ */
++
++ rar->length = high - low + 1;
++
++ /* Claim RAR memory as our own. */
++ if (request_mem_region(low, rar->length, devname) == NULL) {
++ rar->length = 0;
++
++ pr_err("%s: Unable to claim RAR[%d] memory.\n",
++ devname,
++ z);
++ pr_err("%s: RAR[%d] disabled.\n", devname, z);
++
++ /*
++ * Rather than break out of the loop by
++ * returning -EBUSY, for example, we may be
++ * able to claim memory of the next RAR region
++ * as our own.
++ */
++ continue;
++ }
++
++ rar->base = low;
++
++ /*
++ * Now map it into the kernel address space.
++ *
++ * Note that the RAR memory may only be accessed by IA
++ * when debugging. Otherwise attempts to access the
++ * RAR memory when it is locked down will result in
++ * behavior similar to writing to /dev/null and
++ * reading from /dev/zero. This behavior is enforced
++ * by the hardware. Even if we don't access the
++ * memory, mapping it into the kernel provides us with
++ * a convenient RAR handle to bus address mapping.
++ */
++ rar->iobase = ioremap_nocache(rar->base, rar->length);
++ if (rar->iobase == NULL) {
++ pr_err("%s: Unable to map RAR memory.\n",
++ devname);
++ return -ENOMEM;
++ }
++
++ /* Initialize corresponding memory allocator. */
++ rar->allocator = memrar_create_allocator(
++ (unsigned long) rar->iobase,
++ rar->length,
++ RAR_BLOCK_SIZE);
++ if (rar->allocator == NULL)
++ return -1;
++
++ /*
++ * -------------------------------------------------
++ * Make sure all RARs handled by us are locked down.
++ * -------------------------------------------------
++ */
++
++ /* Enable RAR protection on the Lincroft side. */
++ if (0) {
++ /*
++ * This is mostly a sanity check since the
++ * vendor should have locked down RAR in the
++ * SMIP header RAR configuration.
++ */
++ rar_lock(z);
++ } else {
++ pr_warning("%s: LNC RAR[%d] no lock sanity check.\n",
++ devname,
++ z);
++ }
++
++ /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
++ /* |||||||||||||||||||||||||||||||||||||||||||||||||| */
++
++ /*
++ * It would be nice if we could verify that RAR
++ * protection on the Langwell side is enabled, but
++ * there is no way to do that from here. The
++ * necessary Langwell RAR registers are not accessible
++ * from the Lincroft (IA) side.
++ *
++ * Hopefully the ODM did the right thing and enabled
++ * Langwell side RAR protection in the integrated
++ * firmware SMIP header.
++ */
++
++ pr_info("%s: BRAR[%d] bus address range = "
++ "[0x%lx, 0x%lx]\n",
++ devname,
++ z,
++ (unsigned long) low,
++ (unsigned long) high);
++
++ pr_info("%s: BRAR[%d] size = %u KiB\n",
++ devname,
++ z,
++ rar->allocator->capacity / 1024);
++
++ found_rar = 1;
++ }
++
++ if (!found_rar) {
++ /*
++ * No RAR support. Don't bother continuing.
++ *
++ * Note that this is not a failure.
++ */
++ pr_info("%s: No Moorestown RAR support available.\n",
++ devname);
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++/*
++ * Finalize RAR resources.
++ */
++static void memrar_fini_rar_resources(void)
++{
++ int z;
++ struct memrar_buffer_info *pos;
++ struct memrar_buffer_info *tmp;
++
++ /*
++ * @todo Do we need to hold a lock at this point in time?
++ * (module initialization failure or exit?)
++ */
++
++ for (z = MRST_NUM_RAR; z-- != 0; ) {
++ struct memrar_rar_info * const rar = &memrars[z];
++
++ /* Clean up remaining resources. */
++
++ list_for_each_entry_safe(pos,
++ tmp,
++ &rar->buffers.list,
++ list) {
++ kref_put(&pos->refcount, memrar_release_block_i);
++ }
++
++ memrar_destroy_allocator(rar->allocator);
++ rar->allocator = NULL;
++
++ iounmap(rar->iobase);
++ rar->iobase = NULL;
++
++ release_mem_region(rar->base, rar->length);
++ rar->base = 0;
++
++ rar->length = 0;
++ }
++}
++
++static long memrar_reserve_block(struct RAR_buffer *request,
++ struct file *filp)
++{
++ struct RAR_block_info * const rinfo = &request->info;
++ struct RAR_buffer *buffer;
++ struct memrar_buffer_info *buffer_info;
++ u32 handle;
++ struct memrar_rar_info *rar = NULL;
++
++ /* Prevent array overflow. */
++ if (!memrar_is_valid_rar_type(rinfo->type))
++ return -EINVAL;
++
++ rar = &memrars[rinfo->type];
++
++ /* Reserve memory in RAR. */
++ handle = memrar_allocator_alloc(rar->allocator, rinfo->size);
++ if (handle == 0)
++ return -ENOMEM;
++
++ buffer_info = kmalloc(sizeof(*buffer_info), GFP_KERNEL);
++
++ if (buffer_info == NULL) {
++ memrar_allocator_free(rar->allocator, handle);
++ return -ENOMEM;
++ }
++
++ buffer = &buffer_info->buffer;
++ buffer->info.type = rinfo->type;
++ buffer->info.size = rinfo->size;
++
++ /* Memory handle corresponding to the bus address. */
++ buffer->info.handle = handle;
++ buffer->bus_address = memrar_get_bus_address(rar, handle);
++
++ /*
++ * Keep track of owner so that we can later cleanup if
++ * necessary.
++ */
++ buffer_info->owner = filp;
++
++ kref_init(&buffer_info->refcount);
++
++ mutex_lock(&rar->lock);
++ list_add(&buffer_info->list, &rar->buffers.list);
++ mutex_unlock(&rar->lock);
++
++ rinfo->handle = buffer->info.handle;
++ request->bus_address = buffer->bus_address;
++
++ return 0;
++}
++
++static long memrar_release_block(u32 addr)
++{
++ struct memrar_buffer_info *pos;
++ struct memrar_buffer_info *tmp;
++ struct memrar_rar_info * const rar = memrar_get_rar_info(addr);
++ long result = -EINVAL;
++
++ if (rar == NULL)
++ return -EFAULT;
++
++ mutex_lock(&rar->lock);
++
++ /*
++ * Iterate through the buffer list to find the corresponding
++ * buffer to be released.
++ */
++ list_for_each_entry_safe(pos,
++ tmp,
++ &rar->buffers.list,
++ list) {
++ struct RAR_block_info * const info =
++ &pos->buffer.info;
++
++ /*
++ * Take into account handle offsets that may have been
++ * added to the base handle, such as in the following
++ * scenario:
++ *
++ * u32 handle = base + offset;
++ * rar_handle_to_bus(handle);
++ * rar_release(handle);
++ */
++ if (addr >= info->handle
++ && addr < (info->handle + info->size)
++ && memrar_is_valid_rar_type(info->type)) {
++ kref_put(&pos->refcount, memrar_release_block_i);
++ result = 0;
++ break;
++ }
++ }
++
++ mutex_unlock(&rar->lock);
++
++ return result;
++}
++
++static long memrar_get_stat(struct RAR_stat *r)
++{
++ long result = -EINVAL;
++
++ if (likely(r != NULL) && memrar_is_valid_rar_type(r->type)) {
++ struct memrar_allocator * const allocator =
++ memrars[r->type].allocator;
++
++ BUG_ON(allocator == NULL);
++
++ /*
++ * Allocator capacity doesn't change over time. No
++ * need to synchronize.
++ */
++ r->capacity = allocator->capacity;
++
++ mutex_lock(&allocator->lock);
++
++ r->largest_block_size = allocator->largest_free_area;
++
++ mutex_unlock(&allocator->lock);
++
++ result = 0;
++ }
++
++ return result;
++}
++
++static long memrar_ioctl(struct file *filp,
++ unsigned int cmd,
++ unsigned long arg)
++{
++ void __user *argp = (void __user *)arg;
++ long result = 0;
++
++ struct RAR_buffer buffer;
++ struct RAR_block_info * const request = &buffer.info;
++ struct RAR_stat rar_info;
++ u32 rar_handle;
++
++ switch (cmd) {
++ case RAR_HANDLER_RESERVE:
++ if (copy_from_user(request,
++ argp,
++ sizeof(*request)))
++ return -EFAULT;
++
++ result = memrar_reserve_block(&buffer, filp);
++ if (result != 0)
++ return result;
++
++ return copy_to_user(argp, request, sizeof(*request));
++
++ case RAR_HANDLER_RELEASE:
++ if (copy_from_user(&rar_handle,
++ argp,
++ sizeof(rar_handle)))
++ return -EFAULT;
++
++ return memrar_release_block(rar_handle);
++
++ case RAR_HANDLER_STAT:
++ if (copy_from_user(&rar_info,
++ argp,
++ sizeof(rar_info)))
++ return -EFAULT;
++
++ /*
++ * Populate the RAR_stat structure based on the RAR
++ * type given by the user
++ */
++ if (memrar_get_stat(&rar_info) != 0)
++ return -EINVAL;
++
++ /*
++ * @todo Do we need to verify destination pointer
++ * "argp" is non-zero? Is that already done by
++ * copy_to_user()?
++ */
++ return copy_to_user(argp,
++ &rar_info,
++ sizeof(rar_info)) ? -EFAULT : 0;
++
++ default:
++ return -ENOTTY;
++ }
++
++ return 0;
++}
++
++static int memrar_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++ /*
++ * This mmap() implementation is predominantly useful for
++ * debugging since the CPU will be prevented from accessing
++ * RAR memory by the hardware when RAR is properly locked
++ * down.
++ *
++ * In order for this implementation to be useful RAR memory
++ * must be not be locked down. However, we only want to do
++ * that when debugging. DO NOT leave RAR memory unlocked in a
++ * deployed device that utilizes RAR.
++ */
++
++ size_t const size = vma->vm_end - vma->vm_start;
++
++ /* Users pass the RAR handle as the mmap() offset parameter. */
++ unsigned long const handle = vma->vm_pgoff << PAGE_SHIFT;
++
++ struct memrar_rar_info * const rar = memrar_get_rar_info(handle);
++
++ unsigned long pfn;
++
++ /* Invalid RAR handle or size passed to mmap(). */
++ if (rar == NULL
++ || handle == 0
++ || size > (handle - (unsigned long) rar->iobase))
++ return -EINVAL;
++
++ /*
++ * Retrieve physical address corresponding to the RAR handle,
++ * and convert it to a page frame.
++ */
++ pfn = memrar_get_physical_address(rar, handle) >> PAGE_SHIFT;
++
++
++ pr_debug("memrar: mapping RAR range [0x%lx, 0x%lx) into user space.\n",
++ handle,
++ handle + size);
++
++ /*
++ * Map RAR memory into user space. This is really only useful
++ * for debugging purposes since the memory won't be
++ * accessible, i.e. reads return zero and writes are ignored,
++ * when RAR access control is enabled.
++ */
++ if (remap_pfn_range(vma,
++ vma->vm_start,
++ pfn,
++ size,
++ vma->vm_page_prot))
++ return -EAGAIN;
++
++ /* vma->vm_ops = &memrar_mem_ops; */
++
++ return 0;
++}
++
++static int memrar_open(struct inode *inode, struct file *filp)
++{
++ /* Nothing to do yet. */
++
++ return 0;
++}
++
++static int memrar_release(struct inode *inode, struct file *filp)
++{
++ /* Free all regions associated with the given file handle. */
++
++ struct memrar_buffer_info *pos;
++ struct memrar_buffer_info *tmp;
++ int z;
++
++ for (z = 0; z != MRST_NUM_RAR; ++z) {
++ struct memrar_rar_info * const rar = &memrars[z];
++
++ mutex_lock(&rar->lock);
++
++ list_for_each_entry_safe(pos,
++ tmp,
++ &rar->buffers.list,
++ list) {
++ if (filp == pos->owner)
++ kref_put(&pos->refcount,
++ memrar_release_block_i);
++ }
++
++ mutex_unlock(&rar->lock);
++ }
++
++ return 0;
++}
++
++/*
++ * This function is part of the kernel space memrar driver API.
++ */
++size_t rar_reserve(struct RAR_buffer *buffers, size_t count)
++{
++ struct RAR_buffer * const end =
++ (buffers == NULL ? buffers : buffers + count);
++ struct RAR_buffer *i;
++
++ size_t reserve_count = 0;
++
++ for (i = buffers; i != end; ++i) {
++ if (memrar_reserve_block(i, NULL) == 0)
++ ++reserve_count;
++ else
++ i->bus_address = 0;
++ }
++
++ return reserve_count;
++}
++EXPORT_SYMBOL(rar_reserve);
++
++/*
++ * This function is part of the kernel space memrar driver API.
++ */
++size_t rar_release(struct RAR_buffer *buffers, size_t count)
++{
++ struct RAR_buffer * const end =
++ (buffers == NULL ? buffers : buffers + count);
++ struct RAR_buffer *i;
++
++ size_t release_count = 0;
++
++ for (i = buffers; i != end; ++i) {
++ u32 * const handle = &i->info.handle;
++ if (memrar_release_block(*handle) == 0) {
++ /*
++ * @todo We assume we should do this each time
++ * the ref count is decremented. Should
++ * we instead only do this when the ref
++ * count has dropped to zero, and the
++ * buffer has been completely
++ * released/unmapped?
++ */
++ *handle = 0;
++ ++release_count;
++ }
++ }
++
++ return release_count;
++}
++EXPORT_SYMBOL(rar_release);
++
++/*
++ * This function is part of the kernel space driver API.
++ */
++size_t rar_handle_to_bus(struct RAR_buffer *buffers, size_t count)
++{
++ struct RAR_buffer * const end =
++ (buffers == NULL ? buffers : buffers + count);
++ struct RAR_buffer *i;
++ struct memrar_buffer_info *pos;
++
++ size_t conversion_count = 0;
++
++ /*
++ * Find all bus addresses corresponding to the given handles.
++ *
++ * @todo Not liking this nested loop. Optimize.
++ */
++ for (i = buffers; i != end; ++i) {
++ struct memrar_rar_info * const rar =
++ memrar_get_rar_info(i->info.handle);
++
++ /*
++ * Check if we have a bogus handle, and then continue
++ * with remaining buffers.
++ */
++ if (rar == NULL) {
++ i->bus_address = 0;
++ continue;
++ }
++
++ mutex_lock(&rar->lock);
++
++ list_for_each_entry(pos, &rar->buffers.list, list) {
++ struct RAR_block_info * const user_info =
++ &pos->buffer.info;
++
++ /*
++ * Take into account handle offsets that may
++ * have been added to the base handle, such as
++ * in the following scenario:
++ *
++ * u32 handle = base + offset;
++ * rar_handle_to_bus(handle);
++ */
++
++ if (i->info.handle >= user_info->handle
++ && i->info.handle < (user_info->handle
++ + user_info->size)) {
++ u32 const offset =
++ i->info.handle - user_info->handle;
++
++ i->info.type = user_info->type;
++ i->info.size = user_info->size - offset;
++ i->bus_address =
++ pos->buffer.bus_address
++ + offset;
++
++ /* Increment the reference count. */
++ kref_get(&pos->refcount);
++
++ ++conversion_count;
++ break;
++ } else {
++ i->bus_address = 0;
++ }
++ }
++
++ mutex_unlock(&rar->lock);
++ }
++
++ return conversion_count;
++}
++EXPORT_SYMBOL(rar_handle_to_bus);
++
++static const struct file_operations memrar_fops = {
++ .owner = THIS_MODULE,
++ .unlocked_ioctl = memrar_ioctl,
++ .mmap = memrar_mmap,
++ .open = memrar_open,
++ .release = memrar_release,
++};
++
++static struct miscdevice memrar_miscdev = {
++ .minor = MISC_DYNAMIC_MINOR, /* dynamic allocation */
++ .name = "memrar", /* /dev/memrar */
++ .fops = &memrar_fops
++};
++
++static char const banner[] __initdata =
++ KERN_INFO
++ "Intel RAR Handler: " MEMRAR_VER " initialized.\n";
++
++static int memrar_registration_callback(void *ctx)
++{
++ /*
++ * We initialize the RAR parameters early on so that we can
++ * discontinue memrar device initialization and registration
++ * if suitably configured RARs are not available.
++ */
++ int result = memrar_init_rar_resources(memrar_miscdev.name);
++
++ if (result != 0)
++ return result;
++
++ result = misc_register(&memrar_miscdev);
++
++ if (result != 0) {
++ pr_err("%s: misc_register() failed.\n",
++ memrar_miscdev.name);
++
++ /* Clean up resources previously reserved. */
++ memrar_fini_rar_resources();
++ }
++
++ return result;
++}
++
++static int __init memrar_init(void)
++{
++ printk(banner);
++
++ return register_rar(&memrar_registration_callback, 0);
++}
++
++static void __exit memrar_exit(void)
++{
++ memrar_fini_rar_resources();
++
++ misc_deregister(&memrar_miscdev);
++}
++
++
++module_init(memrar_init);
++module_exit(memrar_exit);
++
++
++MODULE_AUTHOR("Ossama Othman <ossama.othman@intel.com>");
++MODULE_DESCRIPTION("Intel Restricted Access Region Handler");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_MISCDEV(MISC_DYNAMIC_MINOR);
++MODULE_VERSION(MEMRAR_VER);
++
++
++
++/*
++ Local Variables:
++ c-file-style: "linux"
++ End:
++*/
diff --git a/staging/staging-rtl8192su-add-usb-id-for-0bda-8171.patch b/staging/staging-rtl8192su-add-usb-id-for-0bda-8171.patch
new file mode 100644
index 00000000000000..42a1b509111b31
--- /dev/null
+++ b/staging/staging-rtl8192su-add-usb-id-for-0bda-8171.patch
@@ -0,0 +1,26 @@
+From proski@gnu.org Thu Apr 22 16:46:24 2010
+From: Pavel Roskin <proski@gnu.org>
+Date: Tue, 09 Mar 2010 23:11:07 -0500
+Subject: Staging: rtl8192su: add USB ID for 0bda:8171
+To: Greg KH <greg@kroah.com>
+Cc: devel@driverdev.osuosl.org
+Message-ID: <20100310041106.791.60267.stgit@mj.roinet.com>
+
+
+Signed-off-by: Pavel Roskin <proski@gnu.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/rtl8192su/r8192U_core.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/staging/rtl8192su/r8192U_core.c
++++ b/drivers/staging/rtl8192su/r8192U_core.c
+@@ -113,6 +113,7 @@ u32 rt_global_debug_component = \
+
+ static const struct usb_device_id rtl8192_usb_id_tbl[] = {
+ /* Realtek */
++ {USB_DEVICE(0x0bda, 0x8171)},
+ {USB_DEVICE(0x0bda, 0x8192)},
+ {USB_DEVICE(0x0bda, 0x8709)},
+ /* Corega */
diff --git a/tty/serial-add-driver-for-the-altera-jtag-uart.patch b/tty/serial-add-driver-for-the-altera-jtag-uart.patch
new file mode 100644
index 00000000000000..0dc62ce570a769
--- /dev/null
+++ b/tty/serial-add-driver-for-the-altera-jtag-uart.patch
@@ -0,0 +1,596 @@
+From tklauser@distanz.ch Thu Apr 22 16:23:18 2010
+From: Tobias Klauser <tklauser@distanz.ch>
+Date: Tue, 30 Mar 2010 16:54:41 +0200
+Subject: serial: Add driver for the Altera JTAG UART
+To: linux-serial@vger.kernel.org, Andrew Morton <akpm@linux-foundation.org>
+Cc: Tobias Klauser <tklauser@distanz.ch>, gregkh@suse.de, nios2-dev@sopc.et.ntust.edu.tw, linux-kernel@vger.kernel.org
+Message-ID: <7ee8095973eb373d34a31ca3875fa7b726bdf552.1269960350.git.tklauser@distanz.ch>
+
+
+Add an UART driver for the JTAG UART component available as a SOPC
+(System on Programmable Chip) component for Altera FPGAs.
+
+Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/Kconfig | 21 +
+ drivers/serial/Makefile | 1
+ drivers/serial/altera_jtaguart.c | 504 +++++++++++++++++++++++++++++++++++++++
+ include/linux/altera_jtaguart.h | 16 +
+ include/linux/serial_core.h | 3
+ 5 files changed, 545 insertions(+)
+
+--- a/drivers/serial/Kconfig
++++ b/drivers/serial/Kconfig
+@@ -1506,4 +1506,25 @@ config SERIAL_GRLIB_GAISLER_APBUART_CONS
+ help
+ Support for running a console on the GRLIB APBUART
+
++config SERIAL_ALTERA_JTAGUART
++ tristate "Altera JTAG UART support"
++ select SERIAL_CORE
++ help
++ This driver supports the Altera JTAG UART port.
++
++config SERIAL_ALTERA_JTAGUART_CONSOLE
++ bool "Altera JTAG UART console support"
++ depends on SERIAL_ALTERA_JTAGUART
++ select SERIAL_CORE_CONSOLE
++ help
++ Enable a Altera JTAG UART port to be the system console.
++
++config SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS
++ bool "Bypass output when no connection"
++ depends on SERIAL_ALTERA_JTAGUART_CONSOLE
++ select SERIAL_CORE_CONSOLE
++ help
++ Bypass console output and keep going even if there is no
++ JTAG terminal connection with the host.
++
+ endmenu
+--- a/drivers/serial/Makefile
++++ b/drivers/serial/Makefile
+@@ -83,3 +83,4 @@ obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgd
+ obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
+ obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
+ obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
++obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
+--- /dev/null
++++ b/drivers/serial/altera_jtaguart.c
+@@ -0,0 +1,504 @@
++/*
++ * altera_jtaguart.c -- Altera JTAG UART driver
++ *
++ * Based on mcf.c -- Freescale ColdFire UART driver
++ *
++ * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
++ * (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
++ * (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
++ *
++ * 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.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/console.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/altera_jtaguart.h>
++
++#define DRV_NAME "altera_jtaguart"
++
++/*
++ * Altera JTAG UART register definitions according to the Altera JTAG UART
++ * datasheet: http://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf
++ */
++
++#define ALTERA_JTAGUART_SIZE 8
++
++#define ALTERA_JTAGUART_DATA_REG 0
++
++#define ALTERA_JTAGUART_DATA_DATA_MSK 0x000000FF
++#define ALTERA_JTAGUART_DATA_RVALID_MSK 0x00008000
++#define ALTERA_JTAGUART_DATA_RAVAIL_MSK 0xFFFF0000
++#define ALTERA_JTAGUART_DATA_RAVAIL_OFF 16
++
++#define ALTERA_JTAGUART_CONTROL_REG 4
++
++#define ALTERA_JTAGUART_CONTROL_RE_MSK 0x00000001
++#define ALTERA_JTAGUART_CONTROL_WE_MSK 0x00000002
++#define ALTERA_JTAGUART_CONTROL_RI_MSK 0x00000100
++#define ALTERA_JTAGUART_CONTROL_RI_OFF 8
++#define ALTERA_JTAGUART_CONTROL_WI_MSK 0x00000200
++#define ALTERA_JTAGUART_CONTROL_AC_MSK 0x00000400
++#define ALTERA_JTAGUART_CONTROL_WSPACE_MSK 0xFFFF0000
++#define ALTERA_JTAGUART_CONTROL_WSPACE_OFF 16
++
++/*
++ * Local per-uart structure.
++ */
++struct altera_jtaguart {
++ struct uart_port port;
++ unsigned int sigs; /* Local copy of line sigs */
++ unsigned long imr; /* Local IMR mirror */
++};
++
++static unsigned int altera_jtaguart_tx_empty(struct uart_port *port)
++{
++ return (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
++ ALTERA_JTAGUART_CONTROL_WSPACE_MSK) ? TIOCSER_TEMT : 0;
++}
++
++static unsigned int altera_jtaguart_get_mctrl(struct uart_port *port)
++{
++ return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
++}
++
++static void altera_jtaguart_set_mctrl(struct uart_port *port, unsigned int sigs)
++{
++}
++
++static void altera_jtaguart_start_tx(struct uart_port *port)
++{
++ struct altera_jtaguart *pp =
++ container_of(port, struct altera_jtaguart, port);
++
++ pp->imr |= ALTERA_JTAGUART_CONTROL_WE_MSK;
++ writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
++}
++
++static void altera_jtaguart_stop_tx(struct uart_port *port)
++{
++ struct altera_jtaguart *pp =
++ container_of(port, struct altera_jtaguart, port);
++
++ pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
++ writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
++}
++
++static void altera_jtaguart_stop_rx(struct uart_port *port)
++{
++ struct altera_jtaguart *pp =
++ container_of(port, struct altera_jtaguart, port);
++
++ pp->imr &= ~ALTERA_JTAGUART_CONTROL_RE_MSK;
++ writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
++}
++
++static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state)
++{
++}
++
++static void altera_jtaguart_enable_ms(struct uart_port *port)
++{
++}
++
++static void altera_jtaguart_set_termios(struct uart_port *port,
++ struct ktermios *termios,
++ struct ktermios *old)
++{
++ /* Just copy the old termios settings back */
++ if (old)
++ tty_termios_copy_hw(termios, old);
++}
++
++static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp)
++{
++ struct uart_port *port = &pp->port;
++ unsigned char ch, flag;
++ unsigned long status;
++
++ while ((status = readl(port->membase + ALTERA_JTAGUART_DATA_REG)) &
++ ALTERA_JTAGUART_DATA_RVALID_MSK) {
++ ch = status & ALTERA_JTAGUART_DATA_DATA_MSK;
++ flag = TTY_NORMAL;
++ port->icount.rx++;
++
++ if (uart_handle_sysrq_char(port, ch))
++ continue;
++ uart_insert_char(port, 0, 0, ch, flag);
++ }
++
++ tty_flip_buffer_push(port->state->port.tty);
++}
++
++static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
++{
++ struct uart_port *port = &pp->port;
++ struct circ_buf *xmit = &port->state->xmit;
++ unsigned int pending, count;
++
++ if (port->x_char) {
++ /* Send special char - probably flow control */
++ writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG);
++ port->x_char = 0;
++ port->icount.tx++;
++ return;
++ }
++
++ pending = uart_circ_chars_pending(xmit);
++ if (pending > 0) {
++ count = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
++ ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >>
++ ALTERA_JTAGUART_CONTROL_WSPACE_OFF;
++ if (count > pending)
++ count = pending;
++ if (count > 0) {
++ pending -= count;
++ while (count--) {
++ writel(xmit->buf[xmit->tail],
++ port->membase + ALTERA_JTAGUART_DATA_REG);
++ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++ port->icount.tx++;
++ }
++ if (pending < WAKEUP_CHARS)
++ uart_write_wakeup(port);
++ }
++ }
++
++ if (pending == 0) {
++ pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
++ writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
++ }
++}
++
++static irqreturn_t altera_jtaguart_interrupt(int irq, void *data)
++{
++ struct uart_port *port = data;
++ struct altera_jtaguart *pp =
++ container_of(port, struct altera_jtaguart, port);
++ unsigned int isr;
++
++ isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >>
++ ALTERA_JTAGUART_CONTROL_RI_OFF) & pp->imr;
++
++ spin_lock(&port->lock);
++
++ if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK)
++ altera_jtaguart_rx_chars(pp);
++ if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK)
++ altera_jtaguart_tx_chars(pp);
++
++ spin_unlock(&port->lock);
++
++ return IRQ_RETVAL(isr);
++}
++
++static void altera_jtaguart_config_port(struct uart_port *port, int flags)
++{
++ port->type = PORT_ALTERA_JTAGUART;
++
++ /* Clear mask, so no surprise interrupts. */
++ writel(0, port->membase + ALTERA_JTAGUART_CONTROL_REG);
++}
++
++static int altera_jtaguart_startup(struct uart_port *port)
++{
++ struct altera_jtaguart *pp =
++ container_of(port, struct altera_jtaguart, port);
++ unsigned long flags;
++ int ret;
++
++ ret = request_irq(port->irq, altera_jtaguart_interrupt, IRQF_DISABLED,
++ DRV_NAME, port);
++ if (ret) {
++ pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d "
++ "interrupt vector=%d\n", port->line, port->irq);
++ return ret;
++ }
++
++ spin_lock_irqsave(&port->lock, flags);
++
++ /* Enable RX interrupts now */
++ pp->imr = ALTERA_JTAGUART_CONTROL_RE_MSK;
++ writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
++
++ spin_unlock_irqrestore(&port->lock, flags);
++
++ return 0;
++}
++
++static void altera_jtaguart_shutdown(struct uart_port *port)
++{
++ struct altera_jtaguart *pp =
++ container_of(port, struct altera_jtaguart, port);
++ unsigned long flags;
++
++ spin_lock_irqsave(&port->lock, flags);
++
++ /* Disable all interrupts now */
++ pp->imr = 0;
++ writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
++
++ spin_unlock_irqrestore(&port->lock, flags);
++
++ free_irq(port->irq, port);
++}
++
++static const char *altera_jtaguart_type(struct uart_port *port)
++{
++ return (port->type == PORT_ALTERA_JTAGUART) ? "Altera JTAG UART" : NULL;
++}
++
++static int altera_jtaguart_request_port(struct uart_port *port)
++{
++ /* UARTs always present */
++ return 0;
++}
++
++static void altera_jtaguart_release_port(struct uart_port *port)
++{
++ /* Nothing to release... */
++}
++
++static int altera_jtaguart_verify_port(struct uart_port *port,
++ struct serial_struct *ser)
++{
++ if (ser->type != PORT_UNKNOWN && ser->type != PORT_ALTERA_JTAGUART)
++ return -EINVAL;
++ return 0;
++}
++
++/*
++ * Define the basic serial functions we support.
++ */
++static struct uart_ops altera_jtaguart_ops = {
++ .tx_empty = altera_jtaguart_tx_empty,
++ .get_mctrl = altera_jtaguart_get_mctrl,
++ .set_mctrl = altera_jtaguart_set_mctrl,
++ .start_tx = altera_jtaguart_start_tx,
++ .stop_tx = altera_jtaguart_stop_tx,
++ .stop_rx = altera_jtaguart_stop_rx,
++ .enable_ms = altera_jtaguart_enable_ms,
++ .break_ctl = altera_jtaguart_break_ctl,
++ .startup = altera_jtaguart_startup,
++ .shutdown = altera_jtaguart_shutdown,
++ .set_termios = altera_jtaguart_set_termios,
++ .type = altera_jtaguart_type,
++ .request_port = altera_jtaguart_request_port,
++ .release_port = altera_jtaguart_release_port,
++ .config_port = altera_jtaguart_config_port,
++ .verify_port = altera_jtaguart_verify_port,
++};
++
++#define ALTERA_JTAGUART_MAXPORTS 1
++static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
++
++#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE)
++
++int __init early_altera_jtaguart_setup(struct altera_jtaguart_platform_uart
++ *platp)
++{
++ struct uart_port *port;
++ int i;
++
++ for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) {
++ port = &altera_jtaguart_ports[i].port;
++
++ port->line = i;
++ port->type = PORT_ALTERA_JTAGUART;
++ port->mapbase = platp[i].mapbase;
++ port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
++ port->iotype = SERIAL_IO_MEM;
++ port->irq = platp[i].irq;
++ port->flags = ASYNC_BOOT_AUTOCONF;
++ port->ops = &altera_jtaguart_ops;
++ }
++
++ return 0;
++}
++
++#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS)
++static void altera_jtaguart_console_putc(struct console *co, const char c)
++{
++ struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
++ unsigned long status;
++ unsigned long flags;
++
++ spin_lock_irqsave(&port->lock, flags);
++ while (((status = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG)) &
++ ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
++ if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0) {
++ spin_unlock_irqrestore(&port->lock, flags);
++ return; /* no connection activity */
++ }
++ spin_unlock_irqrestore(&port->lock, flags);
++ cpu_relax();
++ spin_lock_irqsave(&port->lock, flags);
++ }
++ writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
++ spin_unlock_irqrestore(&port->lock, flags);
++}
++#else
++static void altera_jtaguart_console_putc(struct console *co, const char c)
++{
++ struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
++ unsigned long flags;
++
++ spin_lock_irqsave(&port->lock, flags);
++ while ((readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
++ ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
++ spin_unlock_irqrestore(&port->lock, flags);
++ cpu_relax();
++ spin_lock_irqsave(&port->lock, flags);
++ }
++ writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
++ spin_unlock_irqrestore(&port->lock, flags);
++}
++#endif
++
++static void altera_jtaguart_console_write(struct console *co, const char *s,
++ unsigned int count)
++{
++ for (; count; count--, s++) {
++ altera_jtaguart_console_putc(co, *s);
++ if (*s == '\n')
++ altera_jtaguart_console_putc(co, '\r');
++ }
++}
++
++static int __init altera_jtaguart_console_setup(struct console *co,
++ char *options)
++{
++ struct uart_port *port;
++
++ if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS)
++ return -EINVAL;
++ port = &altera_jtaguart_ports[co->index].port;
++ if (port->membase == 0)
++ return -ENODEV;
++ return 0;
++}
++
++static struct uart_driver altera_jtaguart_driver;
++
++static struct console altera_jtaguart_console = {
++ .name = "ttyJ",
++ .write = altera_jtaguart_console_write,
++ .device = uart_console_device,
++ .setup = altera_jtaguart_console_setup,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++ .data = &altera_jtaguart_driver,
++};
++
++static int __init altera_jtaguart_console_init(void)
++{
++ register_console(&altera_jtaguart_console);
++ return 0;
++}
++
++console_initcall(altera_jtaguart_console_init);
++
++#define ALTERA_JTAGUART_CONSOLE (&altera_jtaguart_console)
++
++#else
++
++#define ALTERA_JTAGUART_CONSOLE NULL
++
++#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */
++
++static struct uart_driver altera_jtaguart_driver = {
++ .owner = THIS_MODULE,
++ .driver_name = "altera_jtaguart",
++ .dev_name = "ttyJ",
++ .major = ALTERA_JTAGUART_MAJOR,
++ .minor = ALTERA_JTAGUART_MINOR,
++ .nr = ALTERA_JTAGUART_MAXPORTS,
++ .cons = ALTERA_JTAGUART_CONSOLE,
++};
++
++static int __devinit altera_jtaguart_probe(struct platform_device *pdev)
++{
++ struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data;
++ struct uart_port *port;
++ int i;
++
++ for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) {
++ port = &altera_jtaguart_ports[i].port;
++
++ port->line = i;
++ port->type = PORT_ALTERA_JTAGUART;
++ port->mapbase = platp[i].mapbase;
++ port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
++ port->iotype = SERIAL_IO_MEM;
++ port->irq = platp[i].irq;
++ port->ops = &altera_jtaguart_ops;
++ port->flags = ASYNC_BOOT_AUTOCONF;
++
++ uart_add_one_port(&altera_jtaguart_driver, port);
++ }
++
++ return 0;
++}
++
++static int __devexit altera_jtaguart_remove(struct platform_device *pdev)
++{
++ struct uart_port *port;
++ int i;
++
++ for (i = 0; i < ALTERA_JTAGUART_MAXPORTS; i++) {
++ port = &altera_jtaguart_ports[i].port;
++ if (port)
++ uart_remove_one_port(&altera_jtaguart_driver, port);
++ }
++
++ return 0;
++}
++
++static struct platform_driver altera_jtaguart_platform_driver = {
++ .probe = altera_jtaguart_probe,
++ .remove = __devexit_p(altera_jtaguart_remove),
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init altera_jtaguart_init(void)
++{
++ int rc;
++
++ rc = uart_register_driver(&altera_jtaguart_driver);
++ if (rc)
++ return rc;
++ rc = platform_driver_register(&altera_jtaguart_platform_driver);
++ if (rc) {
++ uart_unregister_driver(&altera_jtaguart_driver);
++ return rc;
++ }
++ return 0;
++}
++
++static void __exit altera_jtaguart_exit(void)
++{
++ platform_driver_unregister(&altera_jtaguart_platform_driver);
++ uart_unregister_driver(&altera_jtaguart_driver);
++}
++
++module_init(altera_jtaguart_init);
++module_exit(altera_jtaguart_exit);
++
++MODULE_DESCRIPTION("Altera JTAG UART driver");
++MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:" DRV_NAME);
+--- /dev/null
++++ b/include/linux/altera_jtaguart.h
+@@ -0,0 +1,16 @@
++/*
++ * altera_jtaguart.h -- Altera JTAG UART driver defines.
++ */
++
++#ifndef __ALTJUART_H
++#define __ALTJUART_H
++
++#define ALTERA_JTAGUART_MAJOR 204
++#define ALTERA_JTAGUART_MINOR 186
++
++struct altera_jtaguart_platform_uart {
++ unsigned long mapbase; /* Physical address base */
++ unsigned int irq; /* Interrupt vector */
++};
++
++#endif /* __ALTJUART_H */
+--- a/include/linux/serial_core.h
++++ b/include/linux/serial_core.h
+@@ -182,6 +182,9 @@
+ /* Aeroflex Gaisler GRLIB APBUART */
+ #define PORT_APBUART 90
+
++/* Altera UARTs */
++#define PORT_ALTERA_JTAGUART 91
++
+ #ifdef __KERNEL__
+
+ #include <linux/compiler.h>
diff --git a/tty/serial-add-driver-for-the-altera-uart.patch b/tty/serial-add-driver-for-the-altera-uart.patch
new file mode 100644
index 00000000000000..11bf748a3e6089
--- /dev/null
+++ b/tty/serial-add-driver-for-the-altera-uart.patch
@@ -0,0 +1,668 @@
+From tklauser@distanz.ch Thu Apr 22 16:23:33 2010
+From: Tobias Klauser <tklauser@distanz.ch>
+Date: Tue, 30 Mar 2010 16:54:42 +0200
+Subject: serial: Add driver for the Altera UART
+To: linux-serial@vger.kernel.org, Andrew Morton <akpm@linux-foundation.org>
+Cc: Tobias Klauser <tklauser@distanz.ch>, gregkh@suse.de, nios2-dev@sopc.et.ntust.edu.tw, linux-kernel@vger.kernel.org
+Message-ID: <4aaf40955bf19f8dbf0afae5d1cb602fc6e8bf0b.1269960350.git.tklauser@distanz.ch>
+
+
+Add an UART driver for the UART component available as a SOPC (System on
+Programmable Chip) component for Altera FPGAs.
+
+Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/Kconfig | 31 ++
+ drivers/serial/Makefile | 1
+ drivers/serial/altera_uart.c | 570 +++++++++++++++++++++++++++++++++++++++++++
+ include/linux/altera_uart.h | 14 +
+ include/linux/serial_core.h | 1
+ 5 files changed, 617 insertions(+)
+
+--- a/drivers/serial/Kconfig
++++ b/drivers/serial/Kconfig
+@@ -1527,4 +1527,35 @@ config SERIAL_ALTERA_JTAGUART_CONSOLE_BY
+ Bypass console output and keep going even if there is no
+ JTAG terminal connection with the host.
+
++config SERIAL_ALTERA_UART
++ tristate "Altera UART support"
++ select SERIAL_CORE
++ help
++ This driver supports the Altera softcore UART port.
++
++config SERIAL_ALTERA_UART_MAXPORTS
++ int "Maximum number of Altera UART ports"
++ depends on SERIAL_ALTERA_UART
++ default 4
++ help
++ This setting lets you define the maximum number of the Altera
++ UART ports. The usual default varies from board to board, and
++ this setting is a way of catering for that.
++
++config SERIAL_ALTERA_UART_BAUDRATE
++ int "Default baudrate for Altera UART ports"
++ depends on SERIAL_ALTERA_UART
++ default 115200
++ help
++ This setting lets you define what the default baudrate is for the
++ Altera UART ports. The usual default varies from board to board,
++ and this setting is a way of catering for that.
++
++config SERIAL_ALTERA_UART_CONSOLE
++ bool "Altera UART console support"
++ depends on SERIAL_ALTERA_UART
++ select SERIAL_CORE_CONSOLE
++ help
++ Enable a Altera UART port to be the system console.
++
+ endmenu
+--- a/drivers/serial/Makefile
++++ b/drivers/serial/Makefile
+@@ -84,3 +84,4 @@ obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
+ obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
+ obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
+ obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
++obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
+--- /dev/null
++++ b/drivers/serial/altera_uart.c
+@@ -0,0 +1,570 @@
++/*
++ * altera_uart.c -- Altera UART driver
++ *
++ * Based on mcf.c -- Freescale ColdFire UART driver
++ *
++ * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
++ * (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
++ * (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
++ *
++ * 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.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/console.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/altera_uart.h>
++
++#define DRV_NAME "altera_uart"
++
++/*
++ * Altera UART register definitions according to the Nios UART datasheet:
++ * http://www.altera.com/literature/ds/ds_nios_uart.pdf
++ */
++
++#define ALTERA_UART_SIZE 32
++
++#define ALTERA_UART_RXDATA_REG 0
++#define ALTERA_UART_TXDATA_REG 4
++#define ALTERA_UART_STATUS_REG 8
++#define ALTERA_UART_CONTROL_REG 12
++#define ALTERA_UART_DIVISOR_REG 16
++#define ALTERA_UART_EOP_REG 20
++
++#define ALTERA_UART_STATUS_PE_MSK 0x0001 /* parity error */
++#define ALTERA_UART_STATUS_FE_MSK 0x0002 /* framing error */
++#define ALTERA_UART_STATUS_BRK_MSK 0x0004 /* break */
++#define ALTERA_UART_STATUS_ROE_MSK 0x0008 /* RX overrun error */
++#define ALTERA_UART_STATUS_TOE_MSK 0x0010 /* TX overrun error */
++#define ALTERA_UART_STATUS_TMT_MSK 0x0020 /* TX shift register state */
++#define ALTERA_UART_STATUS_TRDY_MSK 0x0040 /* TX ready */
++#define ALTERA_UART_STATUS_RRDY_MSK 0x0080 /* RX ready */
++#define ALTERA_UART_STATUS_E_MSK 0x0100 /* exception condition */
++#define ALTERA_UART_STATUS_DCTS_MSK 0x0400 /* CTS logic-level change */
++#define ALTERA_UART_STATUS_CTS_MSK 0x0800 /* CTS logic state */
++#define ALTERA_UART_STATUS_EOP_MSK 0x1000 /* EOP written/read */
++
++ /* Enable interrupt on... */
++#define ALTERA_UART_CONTROL_PE_MSK 0x0001 /* ...parity error */
++#define ALTERA_UART_CONTROL_FE_MSK 0x0002 /* ...framing error */
++#define ALTERA_UART_CONTROL_BRK_MSK 0x0004 /* ...break */
++#define ALTERA_UART_CONTROL_ROE_MSK 0x0008 /* ...RX overrun */
++#define ALTERA_UART_CONTROL_TOE_MSK 0x0010 /* ...TX overrun */
++#define ALTERA_UART_CONTROL_TMT_MSK 0x0020 /* ...TX shift register empty */
++#define ALTERA_UART_CONTROL_TRDY_MSK 0x0040 /* ...TX ready */
++#define ALTERA_UART_CONTROL_RRDY_MSK 0x0080 /* ...RX ready */
++#define ALTERA_UART_CONTROL_E_MSK 0x0100 /* ...exception*/
++
++#define ALTERA_UART_CONTROL_TRBK_MSK 0x0200 /* TX break */
++#define ALTERA_UART_CONTROL_DCTS_MSK 0x0400 /* Interrupt on CTS change */
++#define ALTERA_UART_CONTROL_RTS_MSK 0x0800 /* RTS signal */
++#define ALTERA_UART_CONTROL_EOP_MSK 0x1000 /* Interrupt on EOP */
++
++/*
++ * Local per-uart structure.
++ */
++struct altera_uart {
++ struct uart_port port;
++ unsigned int sigs; /* Local copy of line sigs */
++ unsigned short imr; /* Local IMR mirror */
++};
++
++static unsigned int altera_uart_tx_empty(struct uart_port *port)
++{
++ return (readl(port->membase + ALTERA_UART_STATUS_REG) &
++ ALTERA_UART_STATUS_TMT_MSK) ? TIOCSER_TEMT : 0;
++}
++
++static unsigned int altera_uart_get_mctrl(struct uart_port *port)
++{
++ struct altera_uart *pp = container_of(port, struct altera_uart, port);
++ unsigned long flags;
++ unsigned int sigs;
++
++ spin_lock_irqsave(&port->lock, flags);
++ sigs =
++ (readl(port->membase + ALTERA_UART_STATUS_REG) &
++ ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0;
++ sigs |= (pp->sigs & TIOCM_RTS);
++ spin_unlock_irqrestore(&port->lock, flags);
++
++ return sigs;
++}
++
++static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs)
++{
++ struct altera_uart *pp = container_of(port, struct altera_uart, port);
++ unsigned long flags;
++
++ spin_lock_irqsave(&port->lock, flags);
++ pp->sigs = sigs;
++ if (sigs & TIOCM_RTS)
++ pp->imr |= ALTERA_UART_CONTROL_RTS_MSK;
++ else
++ pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK;
++ writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
++ spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static void altera_uart_start_tx(struct uart_port *port)
++{
++ struct altera_uart *pp = container_of(port, struct altera_uart, port);
++ unsigned long flags;
++
++ spin_lock_irqsave(&port->lock, flags);
++ pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK;
++ writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
++ spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static void altera_uart_stop_tx(struct uart_port *port)
++{
++ struct altera_uart *pp = container_of(port, struct altera_uart, port);
++ unsigned long flags;
++
++ spin_lock_irqsave(&port->lock, flags);
++ pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
++ writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
++ spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static void altera_uart_stop_rx(struct uart_port *port)
++{
++ struct altera_uart *pp = container_of(port, struct altera_uart, port);
++ unsigned long flags;
++
++ spin_lock_irqsave(&port->lock, flags);
++ pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK;
++ writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
++ spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static void altera_uart_break_ctl(struct uart_port *port, int break_state)
++{
++ struct altera_uart *pp = container_of(port, struct altera_uart, port);
++ unsigned long flags;
++
++ spin_lock_irqsave(&port->lock, flags);
++ if (break_state == -1)
++ pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK;
++ else
++ pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK;
++ writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
++ spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static void altera_uart_enable_ms(struct uart_port *port)
++{
++}
++
++static void altera_uart_set_termios(struct uart_port *port,
++ struct ktermios *termios,
++ struct ktermios *old)
++{
++ unsigned long flags;
++ unsigned int baud, baudclk;
++
++ baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
++ baudclk = port->uartclk / baud;
++
++ if (old)
++ tty_termios_copy_hw(termios, old);
++ tty_termios_encode_baud_rate(termios, baud, baud);
++
++ spin_lock_irqsave(&port->lock, flags);
++ writel(baudclk, port->membase + ALTERA_UART_DIVISOR_REG);
++ spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static void altera_uart_rx_chars(struct altera_uart *pp)
++{
++ struct uart_port *port = &pp->port;
++ unsigned char ch, flag;
++ unsigned short status;
++
++ while ((status = readl(port->membase + ALTERA_UART_STATUS_REG)) &
++ ALTERA_UART_STATUS_RRDY_MSK) {
++ ch = readl(port->membase + ALTERA_UART_RXDATA_REG);
++ flag = TTY_NORMAL;
++ port->icount.rx++;
++
++ if (status & ALTERA_UART_STATUS_E_MSK) {
++ writel(status, port->membase + ALTERA_UART_STATUS_REG);
++
++ if (status & ALTERA_UART_STATUS_BRK_MSK) {
++ port->icount.brk++;
++ if (uart_handle_break(port))
++ continue;
++ } else if (status & ALTERA_UART_STATUS_PE_MSK) {
++ port->icount.parity++;
++ } else if (status & ALTERA_UART_STATUS_ROE_MSK) {
++ port->icount.overrun++;
++ } else if (status & ALTERA_UART_STATUS_FE_MSK) {
++ port->icount.frame++;
++ }
++
++ status &= port->read_status_mask;
++
++ if (status & ALTERA_UART_STATUS_BRK_MSK)
++ flag = TTY_BREAK;
++ else if (status & ALTERA_UART_STATUS_PE_MSK)
++ flag = TTY_PARITY;
++ else if (status & ALTERA_UART_STATUS_FE_MSK)
++ flag = TTY_FRAME;
++ }
++
++ if (uart_handle_sysrq_char(port, ch))
++ continue;
++ uart_insert_char(port, status, ALTERA_UART_STATUS_ROE_MSK, ch,
++ flag);
++ }
++
++ tty_flip_buffer_push(port->state->port.tty);
++}
++
++static void altera_uart_tx_chars(struct altera_uart *pp)
++{
++ struct uart_port *port = &pp->port;
++ struct circ_buf *xmit = &port->state->xmit;
++
++ if (port->x_char) {
++ /* Send special char - probably flow control */
++ writel(port->x_char, port->membase + ALTERA_UART_TXDATA_REG);
++ port->x_char = 0;
++ port->icount.tx++;
++ return;
++ }
++
++ while (readl(port->membase + ALTERA_UART_STATUS_REG) &
++ ALTERA_UART_STATUS_TRDY_MSK) {
++ if (xmit->head == xmit->tail)
++ break;
++ writel(xmit->buf[xmit->tail],
++ port->membase + ALTERA_UART_TXDATA_REG);
++ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++ port->icount.tx++;
++ }
++
++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++ uart_write_wakeup(port);
++
++ if (xmit->head == xmit->tail) {
++ pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
++ writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
++ }
++}
++
++static irqreturn_t altera_uart_interrupt(int irq, void *data)
++{
++ struct uart_port *port = data;
++ struct altera_uart *pp = container_of(port, struct altera_uart, port);
++ unsigned int isr;
++
++ isr = readl(port->membase + ALTERA_UART_STATUS_REG) & pp->imr;
++ if (isr & ALTERA_UART_STATUS_RRDY_MSK)
++ altera_uart_rx_chars(pp);
++ if (isr & ALTERA_UART_STATUS_TRDY_MSK)
++ altera_uart_tx_chars(pp);
++ return IRQ_RETVAL(isr);
++}
++
++static void altera_uart_config_port(struct uart_port *port, int flags)
++{
++ port->type = PORT_ALTERA_UART;
++
++ /* Clear mask, so no surprise interrupts. */
++ writel(0, port->membase + ALTERA_UART_CONTROL_REG);
++ /* Clear status register */
++ writel(0, port->membase + ALTERA_UART_STATUS_REG);
++}
++
++static int altera_uart_startup(struct uart_port *port)
++{
++ struct altera_uart *pp = container_of(port, struct altera_uart, port);
++ unsigned long flags;
++ int ret;
++
++ ret = request_irq(port->irq, altera_uart_interrupt, IRQF_DISABLED,
++ DRV_NAME, port);
++ if (ret) {
++ pr_err(DRV_NAME ": unable to attach Altera UART %d "
++ "interrupt vector=%d\n", port->line, port->irq);
++ return ret;
++ }
++
++ spin_lock_irqsave(&port->lock, flags);
++
++ /* Enable RX interrupts now */
++ pp->imr = ALTERA_UART_CONTROL_RRDY_MSK;
++ writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
++
++ spin_unlock_irqrestore(&port->lock, flags);
++
++ return 0;
++}
++
++static void altera_uart_shutdown(struct uart_port *port)
++{
++ struct altera_uart *pp = container_of(port, struct altera_uart, port);
++ unsigned long flags;
++
++ spin_lock_irqsave(&port->lock, flags);
++
++ /* Disable all interrupts now */
++ pp->imr = 0;
++ writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
++
++ spin_unlock_irqrestore(&port->lock, flags);
++
++ free_irq(port->irq, port);
++}
++
++static const char *altera_uart_type(struct uart_port *port)
++{
++ return (port->type == PORT_ALTERA_UART) ? "Altera UART" : NULL;
++}
++
++static int altera_uart_request_port(struct uart_port *port)
++{
++ /* UARTs always present */
++ return 0;
++}
++
++static void altera_uart_release_port(struct uart_port *port)
++{
++ /* Nothing to release... */
++}
++
++static int altera_uart_verify_port(struct uart_port *port,
++ struct serial_struct *ser)
++{
++ if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_ALTERA_UART))
++ return -EINVAL;
++ return 0;
++}
++
++/*
++ * Define the basic serial functions we support.
++ */
++static struct uart_ops altera_uart_ops = {
++ .tx_empty = altera_uart_tx_empty,
++ .get_mctrl = altera_uart_get_mctrl,
++ .set_mctrl = altera_uart_set_mctrl,
++ .start_tx = altera_uart_start_tx,
++ .stop_tx = altera_uart_stop_tx,
++ .stop_rx = altera_uart_stop_rx,
++ .enable_ms = altera_uart_enable_ms,
++ .break_ctl = altera_uart_break_ctl,
++ .startup = altera_uart_startup,
++ .shutdown = altera_uart_shutdown,
++ .set_termios = altera_uart_set_termios,
++ .type = altera_uart_type,
++ .request_port = altera_uart_request_port,
++ .release_port = altera_uart_release_port,
++ .config_port = altera_uart_config_port,
++ .verify_port = altera_uart_verify_port,
++};
++
++static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
++
++#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
++
++int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp)
++{
++ struct uart_port *port;
++ int i;
++
++ for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
++ port = &altera_uart_ports[i].port;
++
++ port->line = i;
++ port->type = PORT_ALTERA_UART;
++ port->mapbase = platp[i].mapbase;
++ port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
++ port->iotype = SERIAL_IO_MEM;
++ port->irq = platp[i].irq;
++ port->uartclk = platp[i].uartclk;
++ port->flags = ASYNC_BOOT_AUTOCONF;
++ port->ops = &altera_uart_ops;
++ }
++
++ return 0;
++}
++
++static void altera_uart_console_putc(struct console *co, const char c)
++{
++ struct uart_port *port = &(altera_uart_ports + co->index)->port;
++ int i;
++
++ for (i = 0; i < 0x10000; i++) {
++ if (readl(port->membase + ALTERA_UART_STATUS_REG) &
++ ALTERA_UART_STATUS_TRDY_MSK)
++ break;
++ }
++ writel(c, port->membase + ALTERA_UART_TXDATA_REG);
++ for (i = 0; i < 0x10000; i++) {
++ if (readl(port->membase + ALTERA_UART_STATUS_REG) &
++ ALTERA_UART_STATUS_TRDY_MSK)
++ break;
++ }
++}
++
++static void altera_uart_console_write(struct console *co, const char *s,
++ unsigned int count)
++{
++ for (; count; count--, s++) {
++ altera_uart_console_putc(co, *s);
++ if (*s == '\n')
++ altera_uart_console_putc(co, '\r');
++ }
++}
++
++static int __init altera_uart_console_setup(struct console *co, char *options)
++{
++ struct uart_port *port;
++ int baud = CONFIG_SERIAL_ALTERA_UART_BAUDRATE;
++ int bits = 8;
++ int parity = 'n';
++ int flow = 'n';
++
++ if (co->index < 0 || co->index >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS)
++ return -EINVAL;
++ port = &altera_uart_ports[co->index].port;
++ if (port->membase == 0)
++ return -ENODEV;
++
++ if (options)
++ uart_parse_options(options, &baud, &parity, &bits, &flow);
++
++ return uart_set_options(port, co, baud, parity, bits, flow);
++}
++
++static struct uart_driver altera_uart_driver;
++
++static struct console altera_uart_console = {
++ .name = "ttyS",
++ .write = altera_uart_console_write,
++ .device = uart_console_device,
++ .setup = altera_uart_console_setup,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++ .data = &altera_uart_driver,
++};
++
++static int __init altera_uart_console_init(void)
++{
++ register_console(&altera_uart_console);
++ return 0;
++}
++
++console_initcall(altera_uart_console_init);
++
++#define ALTERA_UART_CONSOLE (&altera_uart_console)
++
++#else
++
++#define ALTERA_UART_CONSOLE NULL
++
++#endif /* CONFIG_ALTERA_UART_CONSOLE */
++
++/*
++ * Define the altera_uart UART driver structure.
++ */
++static struct uart_driver altera_uart_driver = {
++ .owner = THIS_MODULE,
++ .driver_name = DRV_NAME,
++ .dev_name = "ttyS",
++ .major = TTY_MAJOR,
++ .minor = 64,
++ .nr = CONFIG_SERIAL_ALTERA_UART_MAXPORTS,
++ .cons = ALTERA_UART_CONSOLE,
++};
++
++static int __devinit altera_uart_probe(struct platform_device *pdev)
++{
++ struct altera_uart_platform_uart *platp = pdev->dev.platform_data;
++ struct uart_port *port;
++ int i;
++
++ for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
++ port = &altera_uart_ports[i].port;
++
++ port->line = i;
++ port->type = PORT_ALTERA_UART;
++ port->mapbase = platp[i].mapbase;
++ port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
++ port->iotype = SERIAL_IO_MEM;
++ port->irq = platp[i].irq;
++ port->uartclk = platp[i].uartclk;
++ port->ops = &altera_uart_ops;
++ port->flags = ASYNC_BOOT_AUTOCONF;
++
++ uart_add_one_port(&altera_uart_driver, port);
++ }
++
++ return 0;
++}
++
++static int altera_uart_remove(struct platform_device *pdev)
++{
++ struct uart_port *port;
++ int i;
++
++ for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS; i++) {
++ port = &altera_uart_ports[i].port;
++ if (port)
++ uart_remove_one_port(&altera_uart_driver, port);
++ }
++
++ return 0;
++}
++
++static struct platform_driver altera_uart_platform_driver = {
++ .probe = altera_uart_probe,
++ .remove = __devexit_p(altera_uart_remove),
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ .pm = NULL,
++ },
++};
++
++static int __init altera_uart_init(void)
++{
++ int rc;
++
++ rc = uart_register_driver(&altera_uart_driver);
++ if (rc)
++ return rc;
++ rc = platform_driver_register(&altera_uart_platform_driver);
++ if (rc) {
++ uart_unregister_driver(&altera_uart_driver);
++ return rc;
++ }
++ return 0;
++}
++
++static void __exit altera_uart_exit(void)
++{
++ platform_driver_unregister(&altera_uart_platform_driver);
++ uart_unregister_driver(&altera_uart_driver);
++}
++
++module_init(altera_uart_init);
++module_exit(altera_uart_exit);
++
++MODULE_DESCRIPTION("Altera UART driver");
++MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:" DRV_NAME);
+--- /dev/null
++++ b/include/linux/altera_uart.h
+@@ -0,0 +1,14 @@
++/*
++ * altera_uart.h -- Altera UART driver defines.
++ */
++
++#ifndef __ALTUART_H
++#define __ALTUART_H
++
++struct altera_uart_platform_uart {
++ unsigned long mapbase; /* Physical address base */
++ unsigned int irq; /* Interrupt vector */
++ unsigned int uartclk; /* UART clock rate */
++};
++
++#endif /* __ALTUART_H */
+--- a/include/linux/serial_core.h
++++ b/include/linux/serial_core.h
+@@ -184,6 +184,7 @@
+
+ /* Altera UARTs */
+ #define PORT_ALTERA_JTAGUART 91
++#define PORT_ALTERA_UART 92
+
+ #ifdef __KERNEL__
+
diff --git a/tty/serial-bfin_sport_uart-add-missing-mapbase-initialization.patch b/tty/serial-bfin_sport_uart-add-missing-mapbase-initialization.patch
new file mode 100644
index 00000000000000..d372aa6d1eac3e
--- /dev/null
+++ b/tty/serial-bfin_sport_uart-add-missing-mapbase-initialization.patch
@@ -0,0 +1,40 @@
+From vapier@gentoo.org Thu Apr 22 16:24:46 2010
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Tue, 9 Mar 2010 12:25:31 -0500
+Subject: serial: bfin_sport_uart: add missing mapbase initialization
+To: linux-serial@vger.kernel.org, Alan Cox <alan@lxorguk.ukuu.org.uk>
+Cc: Andrew Morton <akpm@linux-foundation.org>, linux-kernel@vger.kernel.org, uclinux-dist-devel@blackfin.uclinux.org, Sonic Zhang <sonic.zhang@analog.com>
+Message-ID: <1268155540-8241-5-git-send-email-vapier@gentoo.org>
+
+
+From: Sonic Zhang <sonic.zhang@analog.com>
+
+The driver doesn't care about this, but the common serial core wants it.
+
+Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/bfin_sport_uart.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/serial/bfin_sport_uart.c
++++ b/drivers/serial/bfin_sport_uart.c
+@@ -712,6 +712,7 @@ static int __devinit sport_uart_probe(st
+ ret = -ENXIO;
+ goto out_error_free_peripherals;
+ }
++ sport->port.mapbase = res->start;
+
+ sport->port.irq = platform_get_irq(pdev, 0);
+ if (sport->port.irq < 0) {
+@@ -809,7 +810,7 @@ static int __init sport_uart_init(void)
+ {
+ int ret;
+
+- pr_info("Serial: Blackfin uart over sport driver\n");
++ pr_info("Blackfin uart over sport driver\n");
+
+ ret = uart_register_driver(&sport_uart_reg);
+ if (ret) {
diff --git a/tty/serial-bfin_sport_uart-add-support-for-cts-rts-via-gpios.patch b/tty/serial-bfin_sport_uart-add-support-for-cts-rts-via-gpios.patch
new file mode 100644
index 00000000000000..0ff1f293567ed5
--- /dev/null
+++ b/tty/serial-bfin_sport_uart-add-support-for-cts-rts-via-gpios.patch
@@ -0,0 +1,263 @@
+From vapier@gentoo.org Thu Apr 22 16:25:16 2010
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Tue, 9 Mar 2010 12:25:33 -0500
+Subject: serial: bfin_sport_uart: add support for CTS/RTS via GPIOs
+To: linux-serial@vger.kernel.org, Alan Cox <alan@lxorguk.ukuu.org.uk>
+Cc: Andrew Morton <akpm@linux-foundation.org>, linux-kernel@vger.kernel.org, uclinux-dist-devel@blackfin.uclinux.org, Sonic Zhang <sonic.zhang@analog.com>
+Message-ID: <1268155540-8241-7-git-send-email-vapier@gentoo.org>
+
+
+From: Sonic Zhang <sonic.zhang@analog.com>
+
+Some people need flow control on their ports, so now boards can support
+that via any GPIOs.
+
+Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/Kconfig | 24 ++++++++
+ drivers/serial/bfin_sport_uart.c | 111 +++++++++++++++++++++++++++++++++++----
+ drivers/serial/bfin_sport_uart.h | 11 +++
+ 3 files changed, 135 insertions(+), 11 deletions(-)
+
+--- a/drivers/serial/Kconfig
++++ b/drivers/serial/Kconfig
+@@ -1450,24 +1450,48 @@ config SERIAL_BFIN_SPORT0_UART
+ help
+ Enable UART over SPORT0
+
++config SERIAL_BFIN_SPORT0_UART_CTSRTS
++ bool "Enable UART over SPORT0 hardware flow control"
++ depends on SERIAL_BFIN_SPORT0_UART
++ help
++ Enable hardware flow control in the driver.
++
+ config SERIAL_BFIN_SPORT1_UART
+ bool "Enable UART over SPORT1"
+ depends on SERIAL_BFIN_SPORT
+ help
+ Enable UART over SPORT1
+
++config SERIAL_BFIN_SPORT1_UART_CTSRTS
++ bool "Enable UART over SPORT1 hardware flow control"
++ depends on SERIAL_BFIN_SPORT1_UART
++ help
++ Enable hardware flow control in the driver.
++
+ config SERIAL_BFIN_SPORT2_UART
+ bool "Enable UART over SPORT2"
+ depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
+ help
+ Enable UART over SPORT2
+
++config SERIAL_BFIN_SPORT2_UART_CTSRTS
++ bool "Enable UART over SPORT2 hardware flow control"
++ depends on SERIAL_BFIN_SPORT2_UART
++ help
++ Enable hardware flow control in the driver.
++
+ config SERIAL_BFIN_SPORT3_UART
+ bool "Enable UART over SPORT3"
+ depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
+ help
+ Enable UART over SPORT3
+
++config SERIAL_BFIN_SPORT3_UART_CTSRTS
++ bool "Enable UART over SPORT3 hardware flow control"
++ depends on SERIAL_BFIN_SPORT3_UART
++ help
++ Enable hardware flow control in the driver.
++
+ config SERIAL_TIMBERDALE
+ tristate "Support for timberdale UART"
+ select SERIAL_CORE
+--- a/drivers/serial/bfin_sport_uart.c
++++ b/drivers/serial/bfin_sport_uart.c
+@@ -48,6 +48,10 @@ struct sport_uart_port {
+ unsigned short txmask2;
+ unsigned char stopb;
+ /* unsigned char parib; */
++#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
++ int cts_pin;
++ int rts_pin;
++#endif
+ };
+
+ static void sport_uart_tx_chars(struct sport_uart_port *up);
+@@ -198,6 +202,59 @@ static irqreturn_t sport_uart_err_irq(in
+ return IRQ_HANDLED;
+ }
+
++#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
++static unsigned int sport_get_mctrl(struct uart_port *port)
++{
++ struct sport_uart_port *up = (struct sport_uart_port *)port;
++ if (up->cts_pin < 0)
++ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
++
++ /* CTS PIN is negative assertive. */
++ if (SPORT_UART_GET_CTS(up))
++ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
++ else
++ return TIOCM_DSR | TIOCM_CAR;
++}
++
++static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
++{
++ struct sport_uart_port *up = (struct sport_uart_port *)port;
++ if (up->rts_pin < 0)
++ return;
++
++ /* RTS PIN is negative assertive. */
++ if (mctrl & TIOCM_RTS)
++ SPORT_UART_ENABLE_RTS(up);
++ else
++ SPORT_UART_DISABLE_RTS(up);
++}
++
++/*
++ * Handle any change of modem status signal.
++ */
++static irqreturn_t sport_mctrl_cts_int(int irq, void *dev_id)
++{
++ struct sport_uart_port *up = (struct sport_uart_port *)dev_id;
++ unsigned int status;
++
++ status = sport_get_mctrl(&up->port);
++ uart_handle_cts_change(&up->port, status & TIOCM_CTS);
++
++ return IRQ_HANDLED;
++}
++#else
++static unsigned int sport_get_mctrl(struct uart_port *port)
++{
++ pr_debug("%s enter\n", __func__);
++ return TIOCM_CTS | TIOCM_CD | TIOCM_DSR;
++}
++
++static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
++{
++ pr_debug("%s enter\n", __func__);
++}
++#endif
++
+ /* Reqeust IRQ, Setup clock */
+ static int sport_startup(struct uart_port *port)
+ {
+@@ -226,6 +283,21 @@ static int sport_startup(struct uart_por
+ goto fail2;
+ }
+
++#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
++ if (up->cts_pin >= 0) {
++ if (request_irq(gpio_to_irq(up->cts_pin),
++ sport_mctrl_cts_int,
++ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
++ IRQF_DISABLED, "BFIN_SPORT_UART_CTS", up)) {
++ up->cts_pin = -1;
++ dev_info(port->dev, "Unable to attach BlackFin UART \
++ over SPORT CTS interrupt. So, disable it.\n");
++ }
++ }
++ if (up->rts_pin >= 0)
++ gpio_direction_output(up->rts_pin, 0);
++#endif
++
+ return 0;
+ fail2:
+ free_irq(up->port.irq+1, up);
+@@ -283,17 +355,6 @@ static unsigned int sport_tx_empty(struc
+ return 0;
+ }
+
+-static unsigned int sport_get_mctrl(struct uart_port *port)
+-{
+- pr_debug("%s enter\n", __func__);
+- return (TIOCM_CTS | TIOCM_CD | TIOCM_DSR);
+-}
+-
+-static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
+-{
+- pr_debug("%s enter\n", __func__);
+-}
+-
+ static void sport_stop_tx(struct uart_port *port)
+ {
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+@@ -364,6 +425,10 @@ static void sport_shutdown(struct uart_p
+ free_irq(up->port.irq, up);
+ free_irq(up->port.irq+1, up);
+ free_irq(up->err_irq, up);
++#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
++ if (up->cts_pin >= 0)
++ free_irq(gpio_to_irq(up->cts_pin), up);
++#endif
+ }
+
+ static const char *sport_type(struct uart_port *port)
+@@ -536,7 +601,11 @@ sport_uart_console_setup(struct console
+ int baud = 57600;
+ int bits = 8;
+ int parity = 'n';
++# ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
++ int flow = 'r';
++# else
+ int flow = 'n';
++# endif
+
+ /* Check whether an invalid uart number has been specified */
+ if (co->index < 0 || co->index >= BFIN_SPORT_UART_MAX_PORTS)
+@@ -729,6 +798,22 @@ static int __devinit sport_uart_probe(st
+ ret = -ENOENT;
+ goto out_error_unmap;
+ }
++#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
++ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
++ if (res == NULL)
++ sport->cts_pin = -1;
++ else
++ sport->cts_pin = res->start;
++
++ res = platform_get_resource(pdev, IORESOURCE_IO, 1);
++ if (res == NULL)
++ sport->rts_pin = -1;
++ else
++ sport->rts_pin = res->start;
++
++ if (sport->rts_pin >= 0)
++ gpio_request(sport->rts_pin, DRV_NAME);
++#endif
+ }
+
+ #ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
+@@ -767,6 +852,10 @@ static int __devexit sport_uart_remove(s
+
+ if (sport) {
+ uart_remove_one_port(&sport_uart_reg, &sport->port);
++#ifdef CONFIG_SERIAL_BFIN_CTSRTS
++ if (sport->rts_pin >= 0)
++ gpio_free(sport->rts_pin);
++#endif
+ iounmap(sport->port.membase);
+ peripheral_free_list(
+ (unsigned short *)pdev->dev.platform_data);
+--- a/drivers/serial/bfin_sport_uart.h
++++ b/drivers/serial/bfin_sport_uart.h
+@@ -72,4 +72,15 @@
+
+ #define SPORT_TX_FIFO_SIZE 8
+
++#define SPORT_UART_GET_CTS(x) gpio_get_value(x->cts_pin)
++#define SPORT_UART_DISABLE_RTS(x) gpio_set_value(x->rts_pin, 1)
++#define SPORT_UART_ENABLE_RTS(x) gpio_set_value(x->rts_pin, 0)
++
++#if defined(CONFIG_SERIAL_BFIN_SPORT0_UART_CTSRTS) \
++ || defined(CONFIG_SERIAL_BFIN_SPORT1_UART_CTSRTS) \
++ || defined(CONFIG_SERIAL_BFIN_SPORT2_UART_CTSRTS) \
++ || defined(CONFIG_SERIAL_BFIN_SPORT3_UART_CTSRTS)
++# define CONFIG_SERIAL_BFIN_SPORT_CTSRTS
++#endif
++
+ #endif /* _BFIN_SPORT_UART_H */
diff --git a/tty/serial-bfin_sport_uart-drop-redundant-cpu-depends.patch b/tty/serial-bfin_sport_uart-drop-redundant-cpu-depends.patch
new file mode 100644
index 00000000000000..dbf607148e73c0
--- /dev/null
+++ b/tty/serial-bfin_sport_uart-drop-redundant-cpu-depends.patch
@@ -0,0 +1,29 @@
+From vapier@gentoo.org Thu Apr 22 16:26:35 2010
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Tue, 9 Mar 2010 12:25:40 -0500
+Subject: serial: bfin_sport_uart: drop redundant cpu depends
+To: linux-serial@vger.kernel.org, Alan Cox <alan@lxorguk.ukuu.org.uk>
+Cc: Andrew Morton <akpm@linux-foundation.org>, linux-kernel@vger.kernel.org, uclinux-dist-devel@blackfin.uclinux.org
+Message-ID: <1268155540-8241-14-git-send-email-vapier@gentoo.org>
+
+
+The BF54xM procs imply the related BF54x define, so no need to check both.
+
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/serial/Kconfig
++++ b/drivers/serial/Kconfig
+@@ -1446,7 +1446,7 @@ config SERIAL_BFIN_SPORT_CONSOLE
+
+ config SERIAL_BFIN_SPORT0_UART
+ bool "Enable UART over SPORT0"
+- depends on SERIAL_BFIN_SPORT && !(BF542 || BF542M || BF544 || BF544M)
++ depends on SERIAL_BFIN_SPORT && !(BF542 || BF544)
+ help
+ Enable UART over SPORT0
+
diff --git a/tty/serial-bfin_sport_uart-drop-the-experimental-markings.patch b/tty/serial-bfin_sport_uart-drop-the-experimental-markings.patch
new file mode 100644
index 00000000000000..c4214df95fe080
--- /dev/null
+++ b/tty/serial-bfin_sport_uart-drop-the-experimental-markings.patch
@@ -0,0 +1,31 @@
+From vapier@gentoo.org Thu Apr 22 16:26:25 2010
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Tue, 9 Mar 2010 12:25:39 -0500
+Subject: serial: bfin_sport_uart: drop the experimental markings
+To: linux-serial@vger.kernel.org, Alan Cox <alan@lxorguk.ukuu.org.uk>
+Cc: Andrew Morton <akpm@linux-foundation.org>, linux-kernel@vger.kernel.org, uclinux-dist-devel@blackfin.uclinux.org
+Message-ID: <1268155540-8241-13-git-send-email-vapier@gentoo.org>
+
+
+Should be stable now ...
+
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/Kconfig | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/serial/Kconfig
++++ b/drivers/serial/Kconfig
+@@ -1430,8 +1430,8 @@ config SERIAL_SC26XX_CONSOLE
+ Support for Console on SC2681/SC2692 serial ports.
+
+ config SERIAL_BFIN_SPORT
+- tristate "Blackfin SPORT emulate UART (EXPERIMENTAL)"
+- depends on BLACKFIN && EXPERIMENTAL
++ tristate "Blackfin SPORT emulate UART"
++ depends on BLACKFIN
+ select SERIAL_CORE
+ help
+ Enable SPORT emulate UART on Blackfin series.
diff --git a/tty/serial-bfin_sport_uart-drop-useless-status-masks.patch b/tty/serial-bfin_sport_uart-drop-useless-status-masks.patch
new file mode 100644
index 00000000000000..64b7899f5c40c2
--- /dev/null
+++ b/tty/serial-bfin_sport_uart-drop-useless-status-masks.patch
@@ -0,0 +1,50 @@
+From vapier@gentoo.org Thu Apr 22 16:25:49 2010
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Tue, 9 Mar 2010 12:25:36 -0500
+Subject: serial: bfin_sport_uart: drop useless status masks
+To: linux-serial@vger.kernel.org, Alan Cox <alan@lxorguk.ukuu.org.uk>
+Cc: Andrew Morton <akpm@linux-foundation.org>, linux-kernel@vger.kernel.org, uclinux-dist-devel@blackfin.uclinux.org
+Message-ID: <1268155540-8241-10-git-send-email-vapier@gentoo.org>
+
+
+These were all copied over from the Blackfin UART driver, but they don't
+make sense here because these bits are all specific to the Blackfin UART.
+
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/bfin_sport_uart.c | 17 +----------------
+ 1 file changed, 1 insertion(+), 16 deletions(-)
+
+--- a/drivers/serial/bfin_sport_uart.c
++++ b/drivers/serial/bfin_sport_uart.c
+@@ -500,27 +500,12 @@ static void sport_set_termios(struct uar
+
+ spin_lock_irqsave(&up->port.lock, flags);
+
+- port->read_status_mask = OE;
+- if (termios->c_iflag & INPCK)
+- port->read_status_mask |= (FE | PE);
+- if (termios->c_iflag & (BRKINT | PARMRK))
+- port->read_status_mask |= BI;
++ port->read_status_mask = 0;
+
+ /*
+ * Characters to ignore
+ */
+ port->ignore_status_mask = 0;
+- if (termios->c_iflag & IGNPAR)
+- port->ignore_status_mask |= FE | PE;
+- if (termios->c_iflag & IGNBRK) {
+- port->ignore_status_mask |= BI;
+- /*
+- * If we're ignoring parity and break indicators,
+- * ignore overruns too (for real raw support).
+- */
+- if (termios->c_iflag & IGNPAR)
+- port->ignore_status_mask |= OE;
+- }
+
+ /* RX extract mask */
+ up->rxmask = 0x01 | (((up->csize + up->stopb) * 2 - 1) << 0x8);
diff --git a/tty/serial-bfin_sport_uart-only-enable-sport-tx-if-data-is-to-be-sent.patch b/tty/serial-bfin_sport_uart-only-enable-sport-tx-if-data-is-to-be-sent.patch
new file mode 100644
index 00000000000000..a578973bfc0659
--- /dev/null
+++ b/tty/serial-bfin_sport_uart-only-enable-sport-tx-if-data-is-to-be-sent.patch
@@ -0,0 +1,107 @@
+From vapier@gentoo.org Thu Apr 22 16:26:03 2010
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Tue, 9 Mar 2010 12:25:37 -0500
+Subject: serial: bfin_sport_uart: only enable SPORT TX if data is to be sent
+To: linux-serial@vger.kernel.org, Alan Cox <alan@lxorguk.ukuu.org.uk>
+Cc: Andrew Morton <akpm@linux-foundation.org>, linux-kernel@vger.kernel.org, uclinux-dist-devel@blackfin.uclinux.org, Sonic Zhang <sonic.zhang@analog.com>
+Message-ID: <1268155540-8241-11-git-send-email-vapier@gentoo.org>
+
+
+From: Sonic Zhang <sonic.zhang@analog.com>
+
+Rather than always turn on the SPORT TX interrupt, only do it when we've
+actually queued up data for transmission. This avoids useless interrupt
+processing.
+
+Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/bfin_sport_uart.c | 30 +++++++++++++++++++++---------
+ 1 file changed, 21 insertions(+), 9 deletions(-)
+
+--- a/drivers/serial/bfin_sport_uart.c
++++ b/drivers/serial/bfin_sport_uart.c
+@@ -54,7 +54,7 @@ struct sport_uart_port {
+ #endif
+ };
+
+-static void sport_uart_tx_chars(struct sport_uart_port *up);
++static int sport_uart_tx_chars(struct sport_uart_port *up);
+ static void sport_stop_tx(struct uart_port *port);
+
+ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
+@@ -307,18 +307,24 @@ static int sport_startup(struct uart_por
+ return ret;
+ }
+
+-static void sport_uart_tx_chars(struct sport_uart_port *up)
++/*
++ * sport_uart_tx_chars
++ *
++ * ret 1 means need to enable sport.
++ * ret 0 means do nothing.
++ */
++static int sport_uart_tx_chars(struct sport_uart_port *up)
+ {
+ struct circ_buf *xmit = &up->port.state->xmit;
+
+ if (SPORT_GET_STAT(up) & TXF)
+- return;
++ return 0;
+
+ if (up->port.x_char) {
+ tx_one_byte(up, up->port.x_char);
+ up->port.icount.tx++;
+ up->port.x_char = 0;
+- return;
++ return 1;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+@@ -329,7 +335,7 @@ static void sport_uart_tx_chars(struct s
+ */
+ if (SPORT_GET_STAT(up) & TXHRE)
+ sport_stop_tx(&up->port);
+- return;
++ return 0;
+ }
+
+ while(!(SPORT_GET_STAT(up) & TXF) && !uart_circ_empty(xmit)) {
+@@ -340,6 +346,8 @@ static void sport_uart_tx_chars(struct s
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&up->port);
++
++ return 1;
+ }
+
+ static unsigned int sport_tx_empty(struct uart_port *port)
+@@ -361,6 +369,9 @@ static void sport_stop_tx(struct uart_po
+
+ pr_debug("%s enter\n", __func__);
+
++ if (!(SPORT_GET_TCR1(up) & TSPEN))
++ return;
++
+ /* Although the hold register is empty, last byte is still in shift
+ * register and not sent out yet. So, put a dummy data into TX FIFO.
+ * Then, sport tx stops when last byte is shift out and the dummy
+@@ -383,11 +394,12 @@ static void sport_start_tx(struct uart_p
+ pr_debug("%s enter\n", __func__);
+
+ /* Write data into SPORT FIFO before enable SPROT to transmit */
+- sport_uart_tx_chars(up);
++ if (sport_uart_tx_chars(up)) {
++ /* Enable transmit, then an interrupt will generated */
++ SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
++ SSYNC();
++ }
+
+- /* Enable transmit, then an interrupt will generated */
+- SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
+- SSYNC();
+ pr_debug("%s exit\n", __func__);
+ }
+
diff --git a/tty/serial-bfin_sport_uart-protect-changes-to-uart_port.patch b/tty/serial-bfin_sport_uart-protect-changes-to-uart_port.patch
new file mode 100644
index 00000000000000..5b98396bc865c2
--- /dev/null
+++ b/tty/serial-bfin_sport_uart-protect-changes-to-uart_port.patch
@@ -0,0 +1,42 @@
+From vapier@gentoo.org Thu Apr 22 16:25:28 2010
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Tue, 9 Mar 2010 12:25:34 -0500
+Subject: serial: bfin_sport_uart: protect changes to uart_port
+To: linux-serial@vger.kernel.org, Alan Cox <alan@lxorguk.ukuu.org.uk>
+Cc: Andrew Morton <akpm@linux-foundation.org>, linux-kernel@vger.kernel.org, uclinux-dist-devel@blackfin.uclinux.org, Sonic Zhang <sonic.zhang@analog.com>
+Message-ID: <1268155540-8241-8-git-send-email-vapier@gentoo.org>
+
+
+From: Sonic Zhang <sonic.zhang@analog.com>
+
+Common serial API says we need to grab the port lock before modifying
+the port state to prevent inconsistent state between threads.
+
+Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/bfin_sport_uart.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/serial/bfin_sport_uart.c
++++ b/drivers/serial/bfin_sport_uart.c
+@@ -498,6 +498,8 @@ static void sport_set_termios(struct uar
+ /* up->parib = 1; */
+ }
+
++ spin_lock_irqsave(&up->port.lock, flags);
++
+ port->read_status_mask = OE;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= (FE | PE);
+@@ -538,8 +540,6 @@ static void sport_set_termios(struct uar
+ /* uart baud rate */
+ port->uartclk = uart_get_baud_rate(port, termios, old, 0, get_sclk()/16);
+
+- spin_lock_irqsave(&up->port.lock, flags);
+-
+ /* Disable UART */
+ SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
+ SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN);
diff --git a/tty/serial-bfin_sport_uart-pull-in-bfin_sport.h-for-sport-defines.patch b/tty/serial-bfin_sport_uart-pull-in-bfin_sport.h-for-sport-defines.patch
new file mode 100644
index 00000000000000..704fb4f76efdb6
--- /dev/null
+++ b/tty/serial-bfin_sport_uart-pull-in-bfin_sport.h-for-sport-defines.patch
@@ -0,0 +1,28 @@
+From vapier@gentoo.org Thu Apr 22 16:26:14 2010
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Tue, 9 Mar 2010 12:25:38 -0500
+Subject: serial: bfin_sport_uart: pull in bfin_sport.h for SPORT defines
+To: linux-serial@vger.kernel.org, Alan Cox <alan@lxorguk.ukuu.org.uk>
+Cc: Andrew Morton <akpm@linux-foundation.org>, linux-kernel@vger.kernel.org, uclinux-dist-devel@blackfin.uclinux.org
+Message-ID: <1268155540-8241-12-git-send-email-vapier@gentoo.org>
+
+
+Now that the SPORT MMR defines have been unified, switch over to it.
+
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/bfin_sport_uart.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/serial/bfin_sport_uart.c
++++ b/drivers/serial/bfin_sport_uart.c
+@@ -34,6 +34,7 @@
+ #include <linux/tty_flip.h>
+ #include <linux/serial_core.h>
+
++#include <asm/bfin_sport.h>
+ #include <asm/delay.h>
+ #include <asm/portmux.h>
+
diff --git a/tty/serial-bfin_sport_uart-remove-unused-peripheral-pin-lists.patch b/tty/serial-bfin_sport_uart-remove-unused-peripheral-pin-lists.patch
new file mode 100644
index 00000000000000..e94c12ce6ac91c
--- /dev/null
+++ b/tty/serial-bfin_sport_uart-remove-unused-peripheral-pin-lists.patch
@@ -0,0 +1,51 @@
+From vapier@gentoo.org Thu Apr 22 16:24:35 2010
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Tue, 9 Mar 2010 12:25:30 -0500
+Subject: serial: bfin_sport_uart: remove unused peripheral pin lists
+To: linux-serial@vger.kernel.org, Alan Cox <alan@lxorguk.ukuu.org.uk>
+Cc: Andrew Morton <akpm@linux-foundation.org>, linux-kernel@vger.kernel.org, uclinux-dist-devel@blackfin.uclinux.org, Sonic Zhang <sonic.zhang@analog.com>
+Message-ID: <1268155540-8241-4-git-send-email-vapier@gentoo.org>
+
+
+From: Sonic Zhang <sonic.zhang@analog.com>
+
+All the resources are in the boards files now.
+
+Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/bfin_sport_uart.c | 21 ---------------------
+ 1 file changed, 21 deletions(-)
+
+--- a/drivers/serial/bfin_sport_uart.c
++++ b/drivers/serial/bfin_sport_uart.c
+@@ -39,27 +39,6 @@
+
+ #include "bfin_sport_uart.h"
+
+-#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+-unsigned short bfin_uart_pin_req_sport0[] =
+- {P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, \
+- P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0};
+-#endif
+-#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+-unsigned short bfin_uart_pin_req_sport1[] =
+- {P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, \
+- P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0};
+-#endif
+-#ifdef CONFIG_SERIAL_BFIN_SPORT2_UART
+-unsigned short bfin_uart_pin_req_sport2[] =
+- {P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, P_SPORT2_RFS, \
+- P_SPORT2_DRPRI, P_SPORT2_RSCLK, P_SPORT2_DRSEC, P_SPORT2_DTSEC, 0};
+-#endif
+-#ifdef CONFIG_SERIAL_BFIN_SPORT3_UART
+-unsigned short bfin_uart_pin_req_sport3[] =
+- {P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, P_SPORT3_RFS, \
+- P_SPORT3_DRPRI, P_SPORT3_RSCLK, P_SPORT3_DRSEC, P_SPORT3_DTSEC, 0};
+-#endif
+-
+ struct sport_uart_port {
+ struct uart_port port;
+ int err_irq;
diff --git a/tty/serial-bfin_sport_uart-rename-early-platform-driver-class-string.patch b/tty/serial-bfin_sport_uart-rename-early-platform-driver-class-string.patch
new file mode 100644
index 00000000000000..4e5115c4fdce4f
--- /dev/null
+++ b/tty/serial-bfin_sport_uart-rename-early-platform-driver-class-string.patch
@@ -0,0 +1,52 @@
+From vapier@gentoo.org Thu Apr 22 16:25:05 2010
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Tue, 9 Mar 2010 12:25:32 -0500
+Subject: serial: bfin_sport_uart: rename early platform driver class string
+To: linux-serial@vger.kernel.org, Alan Cox <alan@lxorguk.ukuu.org.uk>
+Cc: Andrew Morton <akpm@linux-foundation.org>, linux-kernel@vger.kernel.org, uclinux-dist-devel@blackfin.uclinux.org, Sonic Zhang <sonic.zhang@analog.com>
+Message-ID: <1268155540-8241-6-git-send-email-vapier@gentoo.org>
+
+
+From: Sonic Zhang <sonic.zhang@analog.com>
+
+Clarifies command line set up for devices between consoles and early
+devices.
+
+Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/bfin_sport_uart.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/serial/bfin_sport_uart.c
++++ b/drivers/serial/bfin_sport_uart.c
+@@ -527,6 +527,8 @@ struct uart_ops sport_uart_ops = {
+ static struct sport_uart_port *bfin_sport_uart_ports[BFIN_SPORT_UART_MAX_PORTS];
+
+ #ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
++#define CLASS_BFIN_SPORT_CONSOLE "bfin-sport-console"
++
+ static int __init
+ sport_uart_console_setup(struct console *co, char *options)
+ {
+@@ -788,7 +790,7 @@ static struct platform_driver sport_uart
+
+ #ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
+ static __initdata struct early_platform_driver early_sport_uart_driver = {
+- .class_str = DRV_NAME,
++ .class_str = CLASS_BFIN_SPORT_CONSOLE,
+ .pdrv = &sport_uart_driver,
+ .requested_id = EARLY_PLATFORM_ID_UNSET,
+ };
+@@ -797,7 +799,8 @@ static int __init sport_uart_rs_console_
+ {
+ early_platform_driver_register(&early_sport_uart_driver, DRV_NAME);
+
+- early_platform_driver_probe(DRV_NAME, BFIN_SPORT_UART_MAX_PORTS, 0);
++ early_platform_driver_probe(CLASS_BFIN_SPORT_CONSOLE,
++ BFIN_SPORT_UART_MAX_PORTS, 0);
+
+ register_console(&sport_uart_console);
+
diff --git a/tty/serial-bfin_sport_uart-shorten-the-sport-tx-waiting-loop.patch b/tty/serial-bfin_sport_uart-shorten-the-sport-tx-waiting-loop.patch
new file mode 100644
index 00000000000000..d0605732118004
--- /dev/null
+++ b/tty/serial-bfin_sport_uart-shorten-the-sport-tx-waiting-loop.patch
@@ -0,0 +1,41 @@
+From vapier@gentoo.org Thu Apr 22 16:24:24 2010
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Tue, 9 Mar 2010 12:25:29 -0500
+Subject: serial: bfin_sport_uart: shorten the SPORT TX waiting loop
+To: linux-serial@vger.kernel.org, Alan Cox <alan@lxorguk.ukuu.org.uk>
+Cc: Andrew Morton <akpm@linux-foundation.org>, linux-kernel@vger.kernel.org, uclinux-dist-devel@blackfin.uclinux.org, Sonic Zhang <sonic.zhang@analog.com>
+Message-ID: <1268155540-8241-3-git-send-email-vapier@gentoo.org>
+
+
+From: Sonic Zhang <sonic.zhang@analog.com>
+
+The waiting loop to stop SPORT TX from TX interrupt is too long. This may
+block the SPORT RX interrupts and cause the RX FIFO to overflow. So, do
+stop sport TX only after the last char in TX FIFO is moved into the shift
+register.
+
+Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/bfin_sport_uart.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/serial/bfin_sport_uart.c
++++ b/drivers/serial/bfin_sport_uart.c
+@@ -271,7 +271,13 @@ static void sport_uart_tx_chars(struct s
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+- sport_stop_tx(&up->port);
++ /* The waiting loop to stop SPORT TX from TX interrupt is
++ * too long. This may block SPORT RX interrupts and cause
++ * RX FIFO overflow. So, do stop sport TX only after the last
++ * char in TX FIFO is moved into the shift register.
++ */
++ if (SPORT_GET_STAT(up) & TXHRE)
++ sport_stop_tx(&up->port);
+ return;
+ }
+
diff --git a/tty/serial-bfin_sport_uart-work-around-anomaly-05000473-make-32bit-fifo-read-atomic.patch b/tty/serial-bfin_sport_uart-work-around-anomaly-05000473-make-32bit-fifo-read-atomic.patch
new file mode 100644
index 00000000000000..5a2901a520dfc8
--- /dev/null
+++ b/tty/serial-bfin_sport_uart-work-around-anomaly-05000473-make-32bit-fifo-read-atomic.patch
@@ -0,0 +1,49 @@
+From vapier@gentoo.org Thu Apr 22 16:24:10 2010
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Tue, 9 Mar 2010 12:25:28 -0500
+Subject: serial: bfin_sport_uart: work around anomaly 05000473 (make 32bit fifo read atomic)
+To: linux-serial@vger.kernel.org, Alan Cox <alan@lxorguk.ukuu.org.uk>
+Cc: Andrew Morton <akpm@linux-foundation.org>, linux-kernel@vger.kernel.org, uclinux-dist-devel@blackfin.uclinux.org, Sonic Zhang <sonic.zhang@analog.com>
+Message-ID: <1268155540-8241-2-git-send-email-vapier@gentoo.org>
+
+
+From: Sonic Zhang <sonic.zhang@analog.com>
+
+We cannot let a 32-bit RX FIFO read be interrupted otherwise a fake RX
+underflow error might be generated.
+
+URL: http://blackfin.uclinux.org/gf/tracker/5145
+
+Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/bfin_sport_uart.h | 16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+--- a/drivers/serial/bfin_sport_uart.h
++++ b/drivers/serial/bfin_sport_uart.h
+@@ -37,7 +37,21 @@
+ #define SPORT_GET_TFSDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_TFSDIV))
+ #define SPORT_GET_TX(sport) bfin_read16(((sport)->port.membase + OFFSET_TX))
+ #define SPORT_GET_RX(sport) bfin_read16(((sport)->port.membase + OFFSET_RX))
+-#define SPORT_GET_RX32(sport) bfin_read32(((sport)->port.membase + OFFSET_RX))
++/*
++ * If another interrupt fires while doing a 32-bit read from RX FIFO,
++ * a fake RX underflow error will be generated. So disable interrupts
++ * to prevent interruption while reading the FIFO.
++ */
++#define SPORT_GET_RX32(sport) \
++({ \
++ unsigned int __ret; \
++ if (ANOMALY_05000473) \
++ local_irq_disable(); \
++ __ret = bfin_read32((sport)->port.membase + OFFSET_RX); \
++ if (ANOMALY_05000473) \
++ local_irq_enable(); \
++ __ret; \
++})
+ #define SPORT_GET_RCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR1))
+ #define SPORT_GET_RCR2(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR2))
+ #define SPORT_GET_RCLKDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_RCLKDIV))
diff --git a/tty/serial-bfin_sport_uart-zero-sport_uart_port-if-allocated-dynamically.patch b/tty/serial-bfin_sport_uart-zero-sport_uart_port-if-allocated-dynamically.patch
new file mode 100644
index 00000000000000..d24feafb26dd46
--- /dev/null
+++ b/tty/serial-bfin_sport_uart-zero-sport_uart_port-if-allocated-dynamically.patch
@@ -0,0 +1,37 @@
+From vapier@gentoo.org Thu Apr 22 16:25:38 2010
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Tue, 9 Mar 2010 12:25:35 -0500
+Subject: serial: bfin_sport_uart: zero sport_uart_port if allocated dynamically
+To: linux-serial@vger.kernel.org, Alan Cox <alan@lxorguk.ukuu.org.uk>
+Cc: Andrew Morton <akpm@linux-foundation.org>, linux-kernel@vger.kernel.org, uclinux-dist-devel@blackfin.uclinux.org, Sonic Zhang <sonic.zhang@analog.com>
+Message-ID: <1268155540-8241-9-git-send-email-vapier@gentoo.org>
+
+
+From: Sonic Zhang <sonic.zhang@analog.com>
+
+Need to initialize the SPORT state rather than using random memory.
+
+Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/bfin_sport_uart.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/serial/bfin_sport_uart.c
++++ b/drivers/serial/bfin_sport_uart.c
+@@ -746,11 +746,11 @@ static int __devinit sport_uart_probe(st
+
+ if (bfin_sport_uart_ports[pdev->id] == NULL) {
+ bfin_sport_uart_ports[pdev->id] =
+- kmalloc(sizeof(struct sport_uart_port), GFP_KERNEL);
++ kzalloc(sizeof(struct sport_uart_port), GFP_KERNEL);
+ sport = bfin_sport_uart_ports[pdev->id];
+ if (!sport) {
+ dev_err(&pdev->dev,
+- "Fail to kmalloc sport_uart_port\n");
++ "Fail to malloc sport_uart_port\n");
+ return -ENOMEM;
+ }
+
diff --git a/tty/serial-tty-new-ldiscs-for-staging.patch b/tty/serial-tty-new-ldiscs-for-staging.patch
new file mode 100644
index 00000000000000..3c6c2af982730e
--- /dev/null
+++ b/tty/serial-tty-new-ldiscs-for-staging.patch
@@ -0,0 +1,32 @@
+From pavan_savoy@ti.com Thu Apr 22 16:28:54 2010
+From: pavan_savoy@ti.com
+Date: Thu, 8 Apr 2010 13:16:52 -0500
+Subject: serial: TTY: new ldiscs for staging
+To: gregkh@suse.de, alan@lxorguk.ukuu.org.uk
+Cc: linux-kernel@vger.kernel.org, npelly@google.com, pavan_savoy@yahoo.co.in, Pavan Savoy <pavan_savoy@ti.com>
+Message-ID: <1270750619-19174-2-git-send-email-pavan_savoy@ti.com>
+
+
+From: Pavan Savoy <pavan_savoy@ti.com>
+
+Push the max ldiscs by a few number to allow ldiscs
+to exist in the staging directory and elsewhere.
+
+Signed-off-by: Pavan Savoy <pavan_savoy@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/linux/tty.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/include/linux/tty.h
++++ b/include/linux/tty.h
+@@ -23,7 +23,7 @@
+ */
+ #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */
+ #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */
+-#define NR_LDISCS 20
++#define NR_LDISCS 30
+
+ /* line disciplines */
+ #define N_TTY 0
diff --git a/usb/usb-add-a-new-quirk-usb_quirk_honor_bnuminterfaces.patch b/usb/usb-add-a-new-quirk-usb_quirk_honor_bnuminterfaces.patch
new file mode 100644
index 00000000000000..a9133f2235e6f7
--- /dev/null
+++ b/usb/usb-add-a-new-quirk-usb_quirk_honor_bnuminterfaces.patch
@@ -0,0 +1,100 @@
+From hdegoede@redhat.com Thu Apr 22 17:02:14 2010
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 29 Mar 2010 12:03:17 +0200
+Subject: USB: Add a new quirk: USB_QUIRK_HONOR_BNUMINTERFACES
+Cc: Alan Stern <stern@rowland.harvard.edu>
+Message-ID: <4BB07AE5.1000706@redhat.com>
+
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+Add a new quirk USB_QUIRK_HONOR_BNUMINTERFACES, when this quirk is
+set and a device has more interface descriptors in a configuration
+then it claims to have in config->bNumInterfaces, ignore all additional
+interfaces.
+
+This is needed for devices which try to hide unused interfaces by only
+lowering config->bNumInterfaces, and which can't handle if you try to talk
+to the "hidden" interfaces.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/config.c | 16 ++++++++++++++--
+ drivers/usb/core/quirks.c | 4 ++++
+ include/linux/usb/quirks.h | 4 ++++
+ 3 files changed, 22 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/core/config.c
++++ b/drivers/usb/core/config.c
+@@ -1,5 +1,6 @@
+ #include <linux/usb.h>
+ #include <linux/usb/ch9.h>
++#include <linux/usb/quirks.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/slab.h>
+@@ -478,9 +479,10 @@ skip_to_next_interface_descriptor:
+ return buffer - buffer0 + i;
+ }
+
+-static int usb_parse_configuration(struct device *ddev, int cfgidx,
++static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
+ struct usb_host_config *config, unsigned char *buffer, int size)
+ {
++ struct device *ddev = &dev->dev;
+ unsigned char *buffer0 = buffer;
+ int cfgno;
+ int nintf, nintf_orig;
+@@ -549,6 +551,16 @@ static int usb_parse_configuration(struc
+ }
+
+ inum = d->bInterfaceNumber;
++
++ if ((dev->quirks & USB_QUIRK_HONOR_BNUMINTERFACES) &&
++ n >= nintf_orig) {
++ dev_warn(ddev, "config %d has more interface "
++ "descriptors, than it declares in "
++ "bNumInterfaces, ignoring interface "
++ "number: %d\n", cfgno, inum);
++ continue;
++ }
++
+ if (inum >= nintf_orig)
+ dev_warn(ddev, "config %d has an invalid "
+ "interface number: %d but max is %d\n",
+@@ -800,7 +812,7 @@ int usb_get_configuration(struct usb_dev
+
+ dev->rawdescriptors[cfgno] = bigbuffer;
+
+- result = usb_parse_configuration(&dev->dev, cfgno,
++ result = usb_parse_configuration(dev, cfgno,
+ &dev->config[cfgno], bigbuffer, length);
+ if (result < 0) {
+ ++cfgno;
+--- a/drivers/usb/core/quirks.c
++++ b/drivers/usb/core/quirks.c
+@@ -71,6 +71,10 @@ static const struct usb_device_id usb_qu
+ /* SKYMEDI USB_DRIVE */
+ { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
+
++ /* BUILDWIN Photo Frame */
++ { USB_DEVICE(0x1908, 0x1315), .driver_info =
++ USB_QUIRK_HONOR_BNUMINTERFACES },
++
+ /* INTEL VALUE SSD */
+ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
+
+--- a/include/linux/usb/quirks.h
++++ b/include/linux/usb/quirks.h
+@@ -22,4 +22,8 @@
+ /*device will morph if reset, don't use reset for handling errors */
+ #define USB_QUIRK_RESET_MORPHS 0x00000010
+
++/* device has more interface descriptions than the bNumInterfaces count,
++ and can't handle talking to these interfaces */
++#define USB_QUIRK_HONOR_BNUMINTERFACES 0x00000020
++
+ #endif /* __LINUX_USB_QUIRKS_H */
diff --git a/usb/usb-fix-serial-build-when-sysrq-is-disabled.patch b/usb/usb-fix-serial-build-when-sysrq-is-disabled.patch
new file mode 100644
index 00000000000000..3972387301c79a
--- /dev/null
+++ b/usb/usb-fix-serial-build-when-sysrq-is-disabled.patch
@@ -0,0 +1,54 @@
+From randy.dunlap@oracle.com Thu Apr 22 16:32:55 2010
+From: Randy Dunlap <randy.dunlap@oracle.com>
+Date: Thu, 25 Mar 2010 11:29:16 -0700
+Subject: usb: fix serial build when SYSRQ is disabled
+To: Stephen Rothwell <sfr@canb.auug.org.au>
+Cc: linux-next@vger.kernel.org, Andrew Morton <akpm@linux-foundation.org>, Greg KH <gregkh@suse.de>
+Message-ID: <4BABAB7C.5000006@oracle.com>
+
+
+From: Randy Dunlap <randy.dunlap@oracle.com>
+
+Fix build error when CONFIG_MAGIC_SYSRQ is not enabled:
+
+drivers/usb/serial/generic.c:566: error: implicit declaration of function 'handle_sysrq'
+
+Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/generic.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/usb/serial/generic.c
++++ b/drivers/usb/serial/generic.c
+@@ -12,6 +12,7 @@
+ #include <linux/kernel.h>
+ #include <linux/errno.h>
+ #include <linux/slab.h>
++#include <linux/sysrq.h>
+ #include <linux/tty.h>
+ #include <linux/tty_flip.h>
+ #include <linux/module.h>
+@@ -558,6 +559,7 @@ void usb_serial_generic_unthrottle(struc
+ }
+ }
+
++#ifdef CONFIG_MAGIC_SYSRQ
+ int usb_serial_handle_sysrq_char(struct tty_struct *tty,
+ struct usb_serial_port *port, unsigned int ch)
+ {
+@@ -571,6 +573,13 @@ int usb_serial_handle_sysrq_char(struct
+ }
+ return 0;
+ }
++#else
++int usb_serial_handle_sysrq_char(struct tty_struct *tty,
++ struct usb_serial_port *port, unsigned int ch)
++{
++ return 0;
++}
++#endif
+ EXPORT_SYMBOL_GPL(usb_serial_handle_sysrq_char);
+
+ int usb_serial_handle_break(struct usb_serial_port *port)
diff --git a/usb/usb-serial-driver-zio-motherboard.patch b/usb/usb-serial-driver-zio-motherboard.patch
new file mode 100644
index 00000000000000..44d0de059d2ae5
--- /dev/null
+++ b/usb/usb-serial-driver-zio-motherboard.patch
@@ -0,0 +1,112 @@
+From vijaykumar@zilogic.com Thu Apr 22 16:27:03 2010
+From: Vijay Kumar <vijaykumar@zilogic.com>
+Date: Wed, 10 Mar 2010 21:17:56 +0530
+Subject: USB Serial Driver: ZIO Motherboard
+To: linux-usb@vger.kernel.org
+Cc: gregkh@suse.de
+Message-ID: <4B97BF2C.5000803@zilogic.com>
+
+
+Add ZIO Motherboard USB serial interface driver.
+
+Signed-off-by: Vijay Kumar B. <vijaykumar@zilogic.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/Kconfig | 8 +++++
+ drivers/usb/serial/Makefile | 1
+ drivers/usb/serial/zio.c | 64 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 73 insertions(+)
+
+--- a/drivers/usb/serial/Kconfig
++++ b/drivers/usb/serial/Kconfig
+@@ -619,6 +619,14 @@ config USB_SERIAL_VIVOPAY_SERIAL
+ To compile this driver as a module, choose M here: the
+ module will be called vivopay-serial.
+
++config USB_SERIAL_ZIO
++ tristate "ZIO Motherboard USB serial interface driver"
++ help
++ Say Y here if you want to use ZIO Motherboard.
++
++ To compile this driver as a module, choose M here: the
++ module will be called zio.
++
+ config USB_SERIAL_DEBUG
+ tristate "USB Debugging Device"
+ help
+--- a/drivers/usb/serial/Makefile
++++ b/drivers/usb/serial/Makefile
+@@ -57,4 +57,5 @@ obj-$(CONFIG_USB_SERIAL_VISOR) += viso
+ obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o
+ obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o
+ obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL) += vivopay-serial.o
++obj-$(CONFIG_USB_SERIAL_ZIO) += zio.o
+
+--- /dev/null
++++ b/drivers/usb/serial/zio.c
+@@ -0,0 +1,64 @@
++/*
++ * ZIO Motherboard USB driver
++ *
++ * Copyright (C) 2010 Zilogic Systems <code@zilogic.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.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/tty.h>
++#include <linux/module.h>
++#include <linux/usb.h>
++#include <linux/usb/serial.h>
++#include <linux/uaccess.h>
++
++static const struct usb_device_id id_table[] = {
++ { USB_DEVICE(0x1CBE, 0x0103) },
++ { },
++};
++MODULE_DEVICE_TABLE(usb, id_table);
++
++static struct usb_driver zio_driver = {
++ .name = "zio",
++ .probe = usb_serial_probe,
++ .disconnect = usb_serial_disconnect,
++ .id_table = id_table,
++ .no_dynamic_id = 1,
++};
++
++static struct usb_serial_driver zio_device = {
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "zio",
++ },
++ .id_table = id_table,
++ .usb_driver = &zio_driver,
++ .num_ports = 1,
++};
++
++static int __init zio_init(void)
++{
++ int retval;
++
++ retval = usb_serial_register(&zio_device);
++ if (retval)
++ return retval;
++ retval = usb_register(&zio_driver);
++ if (retval)
++ usb_serial_deregister(&zio_device);
++ return retval;
++}
++
++static void __exit zio_exit(void)
++{
++ usb_deregister(&zio_driver);
++ usb_serial_deregister(&zio_device);
++}
++
++module_init(zio_init);
++module_exit(zio_exit);
++MODULE_LICENSE("GPL");
diff --git a/version b/version
index 3a35a2a01997f9..48d6bffac16bc1 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-2.6.34-rc4
+2.6.34-rc5