aboutsummaryrefslogtreecommitdiffstats
diff options
authorGreg Kroah-Hartman <gregkh@suse.de>2010-06-16 14:01:08 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2010-06-16 14:01:08 -0700
commitfb1b8406b362f338a732e27201431ff99c6f00ef (patch)
treed2d3bef1da1cae52f2104c34867dfd4c6c1b5a58
parentbe5c268029c811c4bcd5ecde1ea5a3f9356d3f31 (diff)
downloadpatches-fb1b8406b362f338a732e27201431ff99c6f00ef.tar.gz
lots of stuff
rest of tty bkl removal and some usb and other patches
-rw-r--r--driver-core/driver-core-drop-__must_check-from-bus_for_each_drv.patch41
-rw-r--r--driver-core/driver-core-use-kmemdup-in-platform_device_add_resources.patch38
-rw-r--r--driver-core/firmware-loader-embed-device-into-firmware_priv-structure.patch468
-rw-r--r--driver-core/firmware-loader-use-statically-initialized-data-attribute.patch59
-rw-r--r--series39
-rw-r--r--tty/8250-fix-set_ldisc-operation.patch39
-rw-r--r--tty/cdc-acm-remove-dead-code.patch62
-rw-r--r--tty/max3110-sanity-check-a-register.patch53
-rw-r--r--tty/mrst_max3110-add-uart-driver-for-max3110-on-moorestown.patch969
-rw-r--r--tty/serial-add-port-helpers.patch117
-rw-r--r--tty/serial-add-uart_cap_efr-and-uart_cap_sleep-flags-to-16c950-uarts-definition.patch33
-rw-r--r--tty/serial-change-the-wait-for-carrier-locking.patch184
-rw-r--r--tty/serial-trim-locking-on-the-helpers.patch54
-rw-r--r--tty/serial-use-block_til_ready-helper.patch124
-rw-r--r--tty/tty-fix-console_sem-lock-order.patch42
-rw-r--r--tty/tty-implement-btm-as-mutex-instead-of-bkl.patch139
-rw-r--r--tty/tty-introduce-wait_event_interruptible_tty.patch191
-rw-r--r--tty/tty-make-vt-s-have-a-tty_port.patch53
-rw-r--r--tty/tty-move-the-vt_tty-field-from-the-vc_data-into-the-standard-tty_port.patch134
-rw-r--r--tty/tty-never-hold-btm-while-getting-tty_mutex.patch111
-rw-r--r--tty/tty-release-btm-while-sleeping-in-block_til_ready.patch175
-rw-r--r--tty/tty-remove-tty_lock_nested.patch219
-rw-r--r--tty/tty-reorder-ldisc-locking.patch117
-rw-r--r--tty/tty-replace-bkl-with-a-new-tty_lock.patch1041
-rw-r--r--tty/tty-untangle-locking-of-wait_until_sent.patch175
-rw-r--r--tty/vc-locking-clean-up.patch81
-rw-r--r--tty/vt-clean-up-the-code-use-kernel-library.patch41
-rw-r--r--usb.current/usb-ehci-mxc-bail-out-on-transceiver-problems.patch69
-rw-r--r--usb.current/usb-musb-fix-a-bug-by-making-suspend-interrupt-available-in-device-mode.patch49
-rw-r--r--usb.current/usb-otg-ulpi-bail-out-on-read-errors.patch46
-rw-r--r--usb/revert-usb-adding-support-for-htc-smartphones-to-ipaq.patch35
-rw-r--r--usb/usb-add-a-serial-number-parameter-to-g_file_storage-module.patch149
-rw-r--r--usb/usb-conexant-fixed-spacing-and-brace-coding-style-issues.patch66
-rw-r--r--usb/usb-ehci-ehci-1.1-addendum-basic-lpm-feature-support.patch243
-rw-r--r--usb/usb-ehci-ehci-1.1-addendum-enable-per-port-change-detect-bits.patch104
-rw-r--r--usb/usb-ehci-ehci-1.1-addendum-preparation.patch323
-rw-r--r--usb/usb-gadget-langwell_udc.c-printk-needs-a-unsigned-long-long-cast-for-a-dma_t.patch31
-rw-r--r--usb/usb-option-remove-duplicate-amoi_vendor_id.patch41
-rw-r--r--usb/usb-throw-away-custom-hex-digit-methods.patch81
-rw-r--r--usb/usb-uvc-move-constants-and-structures-definitions-to-linux-usb-video.h.patch1044
40 files changed, 7080 insertions, 0 deletions
diff --git a/driver-core/driver-core-drop-__must_check-from-bus_for_each_drv.patch b/driver-core/driver-core-drop-__must_check-from-bus_for_each_drv.patch
new file mode 100644
index 00000000000000..3d90edb92f1b9a
--- /dev/null
+++ b/driver-core/driver-core-drop-__must_check-from-bus_for_each_drv.patch
@@ -0,0 +1,41 @@
+From khali@linux-fr.org Wed Jun 16 13:21:43 2010
+From: Jean Delvare <khali@linux-fr.org>
+Date: Wed, 16 Jun 2010 11:44:18 +0200
+Subject: Driver core: Drop __must_check from bus_for_each_drv()
+To: Andrew Morton <akpm@osdl.org>, Greg Kroah-Hartman <gregkh@suse.de>
+Message-ID: <20100616114418.4a529eb4@hyperion.delvare>
+
+
+There is little rationale for marking bus_for_each_drv() __must_check.
+It is more of an iteration helper than a real function. You don't know
+in advance which callback it will be used on, so you have no clue how
+important it can be to check the returned value. In practice, this
+helper function can be used for best-effort tasks.
+
+As a matter of fact, bus_for_each_dev() is not marked __must_check.
+So remove it from bus_for_each_drv() as well. This is the same that
+was done back in October 2006 by Russell King for
+device_for_each_child(), for exactly the same reasons.
+
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Cc: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/linux/device.h | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/include/linux/device.h
++++ b/include/linux/device.h
+@@ -84,9 +84,8 @@ struct device *bus_find_device_by_name(s
+ struct device *start,
+ const char *name);
+
+-int __must_check bus_for_each_drv(struct bus_type *bus,
+- struct device_driver *start, void *data,
+- int (*fn)(struct device_driver *, void *));
++int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
++ void *data, int (*fn)(struct device_driver *, void *));
+
+ void bus_sort_breadthfirst(struct bus_type *bus,
+ int (*compare)(const struct device *a,
diff --git a/driver-core/driver-core-use-kmemdup-in-platform_device_add_resources.patch b/driver-core/driver-core-use-kmemdup-in-platform_device_add_resources.patch
new file mode 100644
index 00000000000000..908e4e1620ffc1
--- /dev/null
+++ b/driver-core/driver-core-use-kmemdup-in-platform_device_add_resources.patch
@@ -0,0 +1,38 @@
+From u.kleine-koenig@pengutronix.de Wed Jun 16 13:51:16 2010
+From: Uwe Kleine-K�nig <u.kleine-koenig@pengutronix.de>
+Date: Tue, 15 Jun 2010 10:47:55 +0200
+Subject: Driver core: use kmemdup in platform_device_add_resources
+To: linux-kernel@vger.kernel.org
+Cc: Greg Kroah-Hartman <gregkh@suse.de>, Magnus Damm <damm@opensource.se>, "Rafael J. Wysocki" <rjw@sisk.pl>, Paul Mundt <lethal@linux-sh.org>, Dmitry Torokhov <dtor@mail.ru>
+Message-ID: <1276591677-4678-1-git-send-email-u.kleine-koenig@pengutronix.de>
+
+
+This makes platform_device_add_resources look like
+platform_device_add_data.
+
+Signed-off-by: Uwe Kleine-K�nig <u.kleine-koenig@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/base/platform.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/base/platform.c
++++ b/drivers/base/platform.c
+@@ -191,13 +191,13 @@ int platform_device_add_resources(struct
+ {
+ struct resource *r;
+
+- r = kmalloc(sizeof(struct resource) * num, GFP_KERNEL);
++ r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL);
+ if (r) {
+- memcpy(r, res, sizeof(struct resource) * num);
+ pdev->resource = r;
+ pdev->num_resources = num;
++ return 0;
+ }
+- return r ? 0 : -ENOMEM;
++ return -ENOMEM;
+ }
+ EXPORT_SYMBOL_GPL(platform_device_add_resources);
+
diff --git a/driver-core/firmware-loader-embed-device-into-firmware_priv-structure.patch b/driver-core/firmware-loader-embed-device-into-firmware_priv-structure.patch
new file mode 100644
index 00000000000000..8d59cba6f394f2
--- /dev/null
+++ b/driver-core/firmware-loader-embed-device-into-firmware_priv-structure.patch
@@ -0,0 +1,468 @@
+From dmitry.torokhov@gmail.com Wed Jun 16 13:27:32 2010
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Fri, 04 Jun 2010 00:54:43 -0700
+Subject: firmware loader: embed device into firmware_priv structure
+To: Greg KH <greg@kroah.com>
+Cc: linux-kernel@vger.kernel.org
+Message-ID: <20100604075443.15861.45944.stgit@localhost.localdomain>
+
+
+Both these structures have the same lifetime rules so instead of allocating
+and managing them separately embed struct device into struct firmware_priv.
+Also make sure to delete sysfs attributes ourselves instead of expecting
+sysfs to clean up our mess.
+
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/base/firmware_class.c | 255 ++++++++++++++++++++----------------------
+ 1 file changed, 122 insertions(+), 133 deletions(-)
+
+--- a/drivers/base/firmware_class.c
++++ b/drivers/base/firmware_class.c
+@@ -93,22 +93,26 @@ struct firmware_priv {
+ int nr_pages;
+ int page_array_size;
+ struct timer_list timeout;
++ struct device dev;
+ bool nowait;
+ char fw_id[];
+ };
+
+-static void
+-fw_load_abort(struct firmware_priv *fw_priv)
++static struct firmware_priv *to_firmware_priv(struct device *dev)
++{
++ return container_of(dev, struct firmware_priv, dev);
++}
++
++static void fw_load_abort(struct firmware_priv *fw_priv)
+ {
+ set_bit(FW_STATUS_ABORT, &fw_priv->status);
+ wmb();
+ complete(&fw_priv->completion);
+ }
+
+-static ssize_t
+-firmware_timeout_show(struct class *class,
+- struct class_attribute *attr,
+- char *buf)
++static ssize_t firmware_timeout_show(struct class *class,
++ struct class_attribute *attr,
++ char *buf)
+ {
+ return sprintf(buf, "%d\n", loading_timeout);
+ }
+@@ -126,14 +130,14 @@ firmware_timeout_show(struct class *clas
+ *
+ * Note: zero means 'wait forever'.
+ **/
+-static ssize_t
+-firmware_timeout_store(struct class *class,
+- struct class_attribute *attr,
+- const char *buf, size_t count)
++static ssize_t firmware_timeout_store(struct class *class,
++ struct class_attribute *attr,
++ const char *buf, size_t count)
+ {
+ loading_timeout = simple_strtol(buf, NULL, 10);
+ if (loading_timeout < 0)
+ loading_timeout = 0;
++
+ return count;
+ }
+
+@@ -145,21 +149,20 @@ static struct class_attribute firmware_c
+
+ static void fw_dev_release(struct device *dev)
+ {
+- struct firmware_priv *fw_priv = dev_get_drvdata(dev);
++ struct firmware_priv *fw_priv = to_firmware_priv(dev);
+ int i;
+
+ for (i = 0; i < fw_priv->nr_pages; i++)
+ __free_page(fw_priv->pages[i]);
+ kfree(fw_priv->pages);
+ kfree(fw_priv);
+- kfree(dev);
+
+ module_put(THIS_MODULE);
+ }
+
+ static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
+ {
+- struct firmware_priv *fw_priv = dev_get_drvdata(dev);
++ struct firmware_priv *fw_priv = to_firmware_priv(dev);
+
+ if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id))
+ return -ENOMEM;
+@@ -181,8 +184,9 @@ static struct class firmware_class = {
+ static ssize_t firmware_loading_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
+- struct firmware_priv *fw_priv = dev_get_drvdata(dev);
++ struct firmware_priv *fw_priv = to_firmware_priv(dev);
+ int loading = test_bit(FW_STATUS_LOADING, &fw_priv->status);
++
+ return sprintf(buf, "%d\n", loading);
+ }
+
+@@ -218,7 +222,7 @@ static ssize_t firmware_loading_store(st
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+ {
+- struct firmware_priv *fw_priv = dev_get_drvdata(dev);
++ struct firmware_priv *fw_priv = to_firmware_priv(dev);
+ int loading = simple_strtol(buf, NULL, 10);
+ int i;
+
+@@ -276,13 +280,12 @@ static ssize_t firmware_loading_store(st
+
+ static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
+
+-static ssize_t
+-firmware_data_read(struct file *filp, struct kobject *kobj,
+- struct bin_attribute *bin_attr, char *buffer, loff_t offset,
+- size_t count)
++static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
++ struct bin_attribute *bin_attr,
++ char *buffer, loff_t offset, size_t count)
+ {
+ struct device *dev = to_dev(kobj);
+- struct firmware_priv *fw_priv = dev_get_drvdata(dev);
++ struct firmware_priv *fw_priv = to_firmware_priv(dev);
+ struct firmware *fw;
+ ssize_t ret_count;
+
+@@ -321,8 +324,7 @@ out:
+ return ret_count;
+ }
+
+-static int
+-fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
++static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
+ {
+ int pages_needed = ALIGN(min_size, PAGE_SIZE) >> PAGE_SHIFT;
+
+@@ -372,13 +374,12 @@ fw_realloc_buffer(struct firmware_priv *
+ * Data written to the 'data' attribute will be later handed to
+ * the driver as a firmware image.
+ **/
+-static ssize_t
+-firmware_data_write(struct file* filp, struct kobject *kobj,
+- struct bin_attribute *bin_attr, char *buffer,
+- loff_t offset, size_t count)
++static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,
++ struct bin_attribute *bin_attr,
++ char *buffer, loff_t offset, size_t count)
+ {
+ struct device *dev = to_dev(kobj);
+- struct firmware_priv *fw_priv = dev_get_drvdata(dev);
++ struct firmware_priv *fw_priv = to_firmware_priv(dev);
+ struct firmware *fw;
+ ssize_t retval;
+
+@@ -426,107 +427,96 @@ static struct bin_attribute firmware_att
+ .write = firmware_data_write,
+ };
+
+-static void
+-firmware_class_timeout(u_long data)
++static void firmware_class_timeout(u_long data)
+ {
+ struct firmware_priv *fw_priv = (struct firmware_priv *) data;
++
+ fw_load_abort(fw_priv);
+ }
+
+-static int fw_register_device(struct device **dev_p, const char *fw_name,
+- struct device *device)
++static struct firmware_priv *
++fw_create_instance(struct firmware *firmware, const char *fw_name,
++ struct device *device, bool uevent, bool nowait)
+ {
+- int retval;
+- 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;
++ struct firmware_priv *fw_priv;
++ struct device *f_dev;
++ int error;
+
+- if (!fw_priv || !f_dev) {
++ fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
++ if (!fw_priv) {
+ dev_err(device, "%s: kmalloc failed\n", __func__);
+- retval = -ENOMEM;
+- goto error_kfree;
++ error = -ENOMEM;
++ goto err_out;
+ }
+
++ fw_priv->fw = firmware;
++ fw_priv->nowait = nowait;
+ strcpy(fw_priv->fw_id, fw_name);
+ init_completion(&fw_priv->completion);
+- fw_priv->timeout.function = firmware_class_timeout;
+- fw_priv->timeout.data = (u_long) fw_priv;
+- init_timer(&fw_priv->timeout);
++ setup_timer(&fw_priv->timeout,
++ firmware_class_timeout, (u_long) fw_priv);
+
++ f_dev = &fw_priv->dev;
++
++ device_initialize(f_dev);
+ dev_set_name(f_dev, "%s", dev_name(device));
+ f_dev->parent = device;
+ f_dev->class = &firmware_class;
+- dev_set_drvdata(f_dev, fw_priv);
+- dev_set_uevent_suppress(f_dev, 1);
+- retval = device_register(f_dev);
+- if (retval) {
+- dev_err(device, "%s: device_register failed\n", __func__);
+- put_device(f_dev);
+- return retval;
+- }
+- *dev_p = f_dev;
+- return 0;
+-
+-error_kfree:
+- kfree(f_dev);
+- kfree(fw_priv);
+- return retval;
+-}
+-
+-static int fw_setup_device(struct firmware *fw, struct device **dev_p,
+- const char *fw_name, struct device *device,
+- int uevent, bool nowait)
+-{
+- struct device *f_dev;
+- struct firmware_priv *fw_priv;
+- int retval;
+
+- *dev_p = NULL;
+- retval = fw_register_device(&f_dev, fw_name, device);
+- if (retval)
+- goto out;
++ dev_set_uevent_suppress(f_dev, true);
+
+ /* Need to pin this module until class device is destroyed */
+ __module_get(THIS_MODULE);
+
+- fw_priv = dev_get_drvdata(f_dev);
+-
+- fw_priv->nowait = nowait;
++ error = device_add(f_dev);
++ if (error) {
++ dev_err(device, "%s: device_register failed\n", __func__);
++ goto err_put_dev;
++ }
+
+- fw_priv->fw = fw;
+- retval = sysfs_create_bin_file(&f_dev->kobj, &firmware_attr_data);
+- if (retval) {
++ error = device_create_bin_file(f_dev, &firmware_attr_data);
++ if (error) {
+ dev_err(device, "%s: sysfs_create_bin_file failed\n", __func__);
+- goto error_unreg;
++ goto err_del_dev;
+ }
+
+- retval = device_create_file(f_dev, &dev_attr_loading);
+- if (retval) {
++ error = device_create_file(f_dev, &dev_attr_loading);
++ if (error) {
+ dev_err(device, "%s: device_create_file failed\n", __func__);
+- goto error_unreg;
++ goto err_del_bin_attr;
+ }
+
+ if (uevent)
+- dev_set_uevent_suppress(f_dev, 0);
+- *dev_p = f_dev;
+- goto out;
++ dev_set_uevent_suppress(f_dev, false);
++
++ return fw_priv;
++
++err_del_bin_attr:
++ device_remove_bin_file(f_dev, &firmware_attr_data);
++err_del_dev:
++ device_del(f_dev);
++err_put_dev:
++ put_device(f_dev);
++err_out:
++ return ERR_PTR(error);
++}
+
+-error_unreg:
++static void fw_destroy_instance(struct firmware_priv *fw_priv)
++{
++ struct device *f_dev = &fw_priv->dev;
++
++ device_remove_file(f_dev, &dev_attr_loading);
++ device_remove_bin_file(f_dev, &firmware_attr_data);
+ device_unregister(f_dev);
+-out:
+- return retval;
+ }
+
+-static int
+-_request_firmware(const struct firmware **firmware_p, const char *name,
+- struct device *device, int uevent, bool nowait)
++static int _request_firmware(const struct firmware **firmware_p,
++ const char *name, struct device *device,
++ bool uevent, bool nowait)
+ {
+- struct device *f_dev;
+ struct firmware_priv *fw_priv;
+ struct firmware *firmware;
+- int retval;
++ int retval = 0;
+
+ if (!firmware_p)
+ return -EINVAL;
+@@ -547,41 +537,40 @@ _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, nowait);
+- if (retval)
+- goto error_kfree_fw;
+-
+- fw_priv = dev_get_drvdata(f_dev);
++ fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
++ if (IS_ERR(fw_priv)) {
++ retval = PTR_ERR(fw_priv);
++ goto out;
++ }
+
+ if (uevent) {
+- if (loading_timeout > 0) {
+- fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
+- add_timer(&fw_priv->timeout);
+- }
++ if (loading_timeout > 0)
++ mod_timer(&fw_priv->timeout,
++ round_jiffies_up(jiffies +
++ loading_timeout * HZ));
++
++ kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
++ }
+
+- kobject_uevent(&f_dev->kobj, KOBJ_ADD);
+- wait_for_completion(&fw_priv->completion);
+- set_bit(FW_STATUS_DONE, &fw_priv->status);
+- del_timer_sync(&fw_priv->timeout);
+- } else
+- wait_for_completion(&fw_priv->completion);
++ wait_for_completion(&fw_priv->completion);
++
++ set_bit(FW_STATUS_DONE, &fw_priv->status);
++ del_timer_sync(&fw_priv->timeout);
+
+ mutex_lock(&fw_lock);
+- if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) {
++ if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status))
+ retval = -ENOENT;
+- release_firmware(fw_priv->fw);
+- *firmware_p = NULL;
+- }
+ fw_priv->fw = NULL;
+ mutex_unlock(&fw_lock);
+- device_unregister(f_dev);
+- goto out;
+
+-error_kfree_fw:
+- kfree(firmware);
+- *firmware_p = NULL;
++ fw_destroy_instance(fw_priv);
++
+ out:
++ if (retval) {
++ release_firmware(firmware);
++ firmware_p = NULL;
++ }
++
+ return retval;
+ }
+
+@@ -632,23 +621,24 @@ struct firmware_work {
+ int uevent;
+ };
+
+-static int
+-request_firmware_work_func(void *arg)
++static int request_firmware_work_func(void *arg)
+ {
+ struct firmware_work *fw_work = arg;
+ const struct firmware *fw;
+ int ret;
++
+ if (!arg) {
+ WARN_ON(1);
+ return 0;
+ }
+- ret = _request_firmware(&fw, fw_work->name, fw_work->device,
+- fw_work->uevent, true);
+
++ ret = _request_firmware(&fw, fw_work->name, fw_work->device,
++ fw_work->uevent, true);
+ fw_work->cont(fw, fw_work->context);
+
+ module_put(fw_work->module);
+ kfree(fw_work);
++
+ return ret;
+ }
+
+@@ -676,34 +666,33 @@ request_firmware_nowait(
+ void (*cont)(const struct firmware *fw, void *context))
+ {
+ struct task_struct *task;
+- struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
+- gfp);
++ struct firmware_work *fw_work;
+
++ fw_work = kzalloc(sizeof (struct firmware_work), gfp);
+ if (!fw_work)
+ return -ENOMEM;
++
++ fw_work->module = module;
++ fw_work->name = name;
++ fw_work->device = device;
++ fw_work->context = context;
++ fw_work->cont = cont;
++ fw_work->uevent = uevent;
++
+ if (!try_module_get(module)) {
+ kfree(fw_work);
+ return -EFAULT;
+ }
+
+- *fw_work = (struct firmware_work) {
+- .module = module,
+- .name = name,
+- .device = device,
+- .context = context,
+- .cont = cont,
+- .uevent = uevent,
+- };
+-
+ task = kthread_run(request_firmware_work_func, fw_work,
+ "firmware/%s", name);
+-
+ if (IS_ERR(task)) {
+ fw_work->cont(NULL, fw_work->context);
+ module_put(fw_work->module);
+ kfree(fw_work);
+ return PTR_ERR(task);
+ }
++
+ return 0;
+ }
+
diff --git a/driver-core/firmware-loader-use-statically-initialized-data-attribute.patch b/driver-core/firmware-loader-use-statically-initialized-data-attribute.patch
new file mode 100644
index 00000000000000..a6b2674340d6c9
--- /dev/null
+++ b/driver-core/firmware-loader-use-statically-initialized-data-attribute.patch
@@ -0,0 +1,59 @@
+From dmitry.torokhov@gmail.com Wed Jun 16 13:27:20 2010
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Fri, 04 Jun 2010 00:54:37 -0700
+Subject: firmware loader: use statically initialized data attribute
+To: Greg KH <greg@kroah.com>
+Cc: linux-kernel@vger.kernel.org
+Message-ID: <20100604075437.15861.14718.stgit@localhost.localdomain>
+
+
+There is no reason why we are using a template for binary attribute
+and copying it into per-firmware data before registering. Using the
+original works as well.
+
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/base/firmware_class.c | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+--- a/drivers/base/firmware_class.c
++++ b/drivers/base/firmware_class.c
+@@ -87,7 +87,6 @@ static DEFINE_MUTEX(fw_lock);
+
+ struct firmware_priv {
+ struct completion completion;
+- struct bin_attribute attr_data;
+ struct firmware *fw;
+ unsigned long status;
+ struct page **pages;
+@@ -420,8 +419,8 @@ out:
+ return retval;
+ }
+
+-static struct bin_attribute firmware_attr_data_tmpl = {
+- .attr = {.name = "data", .mode = 0644},
++static struct bin_attribute firmware_attr_data = {
++ .attr = { .name = "data", .mode = 0644 },
+ .size = 0,
+ .read = firmware_data_read,
+ .write = firmware_data_write,
+@@ -452,7 +451,6 @@ static int fw_register_device(struct dev
+
+ strcpy(fw_priv->fw_id, fw_name);
+ init_completion(&fw_priv->completion);
+- fw_priv->attr_data = firmware_attr_data_tmpl;
+ fw_priv->timeout.function = firmware_class_timeout;
+ fw_priv->timeout.data = (u_long) fw_priv;
+ init_timer(&fw_priv->timeout);
+@@ -498,8 +496,7 @@ static int fw_setup_device(struct firmwa
+ 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);
++ retval = sysfs_create_bin_file(&f_dev->kobj, &firmware_attr_data);
+ if (retval) {
+ dev_err(device, "%s: sysfs_create_bin_file failed\n", __func__);
+ goto error_unreg;
diff --git a/series b/series
index 83870f5462022c..1358d7e1bfc6a1 100644
--- a/series
+++ b/series
@@ -21,6 +21,9 @@ usb.current/usb-g_serial-fix-tty-cleanup-on-unload.patch
usb.current/usb-gadget-g_fs-possible-invalid-pointer-reference-bug-fixed.patch
usb.current/usb-xhci-fix-bug-in-link-trb-activation-change.patch
usb.current/usb-r8a66597-fix-failure-in-change-of-status.patch
+usb.current/usb-musb-fix-a-bug-by-making-suspend-interrupt-available-in-device-mode.patch
+usb.current/usb-otg-ulpi-bail-out-on-read-errors.patch
+usb.current/usb-ehci-mxc-bail-out-on-transceiver-problems.patch
#################################
# Staging patches for 2.6.35
@@ -44,12 +47,20 @@ driver-core/uio-remove-irqf_disabled-from-uio_sercos3.c.patch
driver-core/uio-remove-irqf_disabled-flag-from-uio_cif.c.patch
driver-core/hotplug-support-kernel-hotplug-sysctl-variable-when-config_net.patch
driver-core/driver-core-internal-struct-dma_coherent_mem-change-type-of-a-member.patch
+driver-core/driver-core-drop-__must_check-from-bus_for_each_drv.patch
+driver-core/firmware-loader-use-statically-initialized-data-attribute.patch
+driver-core/firmware-loader-embed-device-into-firmware_priv-structure.patch
+driver-core/driver-core-use-kmemdup-in-platform_device_add_resources.patch
#####################################
# TTY patches for after 2.6.35 is out
#####################################
tty/n_gsm.c-removed-duplicated-includes.patch
tty/serial-there-s-no-config-console.patch
+tty/vt-clean-up-the-code-use-kernel-library.patch
+tty/serial-add-uart_cap_efr-and-uart_cap_sleep-flags-to-16c950-uarts-definition.patch
+tty/mrst_max3110-add-uart-driver-for-max3110-on-moorestown.patch
+tty/max3110-sanity-check-a-register.patch
# tty bkl removal work
tty/stallion-prune-lock_kernel-calls.patch
@@ -66,6 +77,24 @@ tty/synclink-reworking-locking-a-bit.patch
tty/tty-serial-fix-various-misuses-mishandlings-of-port-tty.patch
tty/tty-serial-fix-tty-back-references-in-termios.patch
tty/tty-serial-fix-tty-referencing-in-set_ldisc.patch
+tty/vc-locking-clean-up.patch
+tty/tty-make-vt-s-have-a-tty_port.patch
+tty/tty-move-the-vt_tty-field-from-the-vc_data-into-the-standard-tty_port.patch
+tty/serial-change-the-wait-for-carrier-locking.patch
+tty/serial-add-port-helpers.patch
+tty/serial-trim-locking-on-the-helpers.patch
+tty/serial-use-block_til_ready-helper.patch
+tty/tty-replace-bkl-with-a-new-tty_lock.patch
+tty/tty-never-hold-btm-while-getting-tty_mutex.patch
+tty/tty-fix-console_sem-lock-order.patch
+tty/cdc-acm-remove-dead-code.patch
+tty/tty-introduce-wait_event_interruptible_tty.patch
+tty/tty-reorder-ldisc-locking.patch
+tty/tty-untangle-locking-of-wait_until_sent.patch
+tty/tty-remove-tty_lock_nested.patch
+tty/tty-implement-btm-as-mutex-instead-of-bkl.patch
+tty/tty-release-btm-while-sleeping-in-block_til_ready.patch
+tty/8250-fix-set_ldisc-operation.patch
###################################
# USB stuff for after 2.6.35 is out
@@ -88,6 +117,16 @@ usb/usb-core-endpoint-fix-coding-styles.patch
usb/usb-otg.h-fix-the-mixup-in-parameters-order.patch
usb/usb-host-eliminate-null-dereference.patch
usb/usb-isd200.c-remove-unnecessary-kmalloc-cast.patch
+usb/usb-throw-away-custom-hex-digit-methods.patch
+usb/usb-uvc-move-constants-and-structures-definitions-to-linux-usb-video.h.patch
+usb/usb-ehci-ehci-1.1-addendum-preparation.patch
+usb/usb-ehci-ehci-1.1-addendum-basic-lpm-feature-support.patch
+usb/usb-ehci-ehci-1.1-addendum-enable-per-port-change-detect-bits.patch
+usb/usb-option-remove-duplicate-amoi_vendor_id.patch
+usb/revert-usb-adding-support-for-htc-smartphones-to-ipaq.patch
+usb/usb-gadget-langwell_udc.c-printk-needs-a-unsigned-long-long-cast-for-a-dma_t.patch
+usb/usb-conexant-fixed-spacing-and-brace-coding-style-issues.patch
+usb/usb-add-a-serial-number-parameter-to-g_file_storage-module.patch
# staging stuff is now in the staging-next tree on git.kernel.org
diff --git a/tty/8250-fix-set_ldisc-operation.patch b/tty/8250-fix-set_ldisc-operation.patch
new file mode 100644
index 00000000000000..fee1599e8cbe0f
--- /dev/null
+++ b/tty/8250-fix-set_ldisc-operation.patch
@@ -0,0 +1,39 @@
+From arnd@arndb.de Wed Jun 16 13:48:20 2010
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Tue, 1 Jun 2010 22:53:11 +0200
+Subject: 8250: fix set_ldisc operation
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>
+Message-ID: <1275425591-8803-32-git-send-email-arnd@arndb.de>
+
+
+The ldisc number now gets passed into ->set_ldisc.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/serial/8250.c | 9 ++-------
+ 1 file changed, 2 insertions(+), 7 deletions(-)
+
+--- a/drivers/serial/8250.c
++++ b/drivers/serial/8250.c
+@@ -2409,14 +2409,9 @@ serial8250_set_termios(struct uart_port
+ }
+
+ static void
+-serial8250_set_ldisc(struct uart_port *port)
++serial8250_set_ldisc(struct uart_port *port, int new)
+ {
+- int line = port->line;
+-
+- if (line >= port->state->port.tty->driver->num)
+- return;
+-
+- if (port->state->port.tty->ldisc->ops->num == N_PPS) {
++ if (new == N_PPS) {
+ port->flags |= UPF_HARDPPS_CD;
+ serial8250_enable_ms(port);
+ } else
diff --git a/tty/cdc-acm-remove-dead-code.patch b/tty/cdc-acm-remove-dead-code.patch
new file mode 100644
index 00000000000000..6b587a7f169571
--- /dev/null
+++ b/tty/cdc-acm-remove-dead-code.patch
@@ -0,0 +1,62 @@
+From arnd@arndb.de Wed Jun 16 13:42:49 2010
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Tue, 1 Jun 2010 22:53:04 +0200
+Subject: cdc-acm: remove dead code
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>
+Message-ID: <1275425591-8803-25-git-send-email-arnd@arndb.de>
+
+
+The wait_event_interruptible_timeout in acm_port_down is
+never reached. Remove it to avoid possible deadlocks
+with the big tty mutex if someone were to start using
+the blocking version of acm_port_down.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/class/cdc-acm.c | 12 +++---------
+ 1 file changed, 3 insertions(+), 9 deletions(-)
+
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -636,19 +636,13 @@ static void acm_tty_unregister(struct ac
+
+ static int acm_tty_chars_in_buffer(struct tty_struct *tty);
+
+-static void acm_port_down(struct acm *acm, int drain)
++static void acm_port_down(struct acm *acm)
+ {
+ int i, nr = acm->rx_buflimit;
+ mutex_lock(&open_mutex);
+ if (acm->dev) {
+ usb_autopm_get_interface(acm->control);
+ acm_set_control(acm, acm->ctrlout = 0);
+- /* try letting the last writes drain naturally */
+- if (drain) {
+- wait_event_interruptible_timeout(acm->drain_wait,
+- (ACM_NW == acm_wb_is_avail(acm)) || !acm->dev,
+- ACM_CLOSE_TIMEOUT * HZ);
+- }
+ usb_kill_urb(acm->ctrlurb);
+ for (i = 0; i < ACM_NW; i++)
+ usb_kill_urb(acm->wb[i].urb);
+@@ -664,7 +658,7 @@ static void acm_tty_hangup(struct tty_st
+ {
+ struct acm *acm = tty->driver_data;
+ tty_port_hangup(&acm->port);
+- acm_port_down(acm, 0);
++ acm_port_down(acm);
+ }
+
+ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
+@@ -685,7 +679,7 @@ static void acm_tty_close(struct tty_str
+ mutex_unlock(&open_mutex);
+ return;
+ }
+- acm_port_down(acm, 0);
++ acm_port_down(acm);
+ tty_port_close_end(&acm->port, tty);
+ tty_port_tty_set(&acm->port, NULL);
+ }
diff --git a/tty/max3110-sanity-check-a-register.patch b/tty/max3110-sanity-check-a-register.patch
new file mode 100644
index 00000000000000..3dd69b4b2095ba
--- /dev/null
+++ b/tty/max3110-sanity-check-a-register.patch
@@ -0,0 +1,53 @@
+From alan@linux.intel.com Wed Jun 16 13:50:26 2010
+From: jianwei.yang <jianwei.yang@intel.com>
+Date: Wed, 16 Jun 2010 14:46:49 +0100
+Subject: max3110 sanity check a register
+To: greg@kroah.com, linux-serial@vger.kernel.org
+Message-ID: <20100616134616.12686.11518.stgit@localhost.localdomain>
+
+
+From: jianwei.yang <jianwei.yang@intel.com>
+
+MAX3111 is the SPI/UART IC installed on the MRST SPI Port Card as a serial
+debug goal, and the SPI Port Card will be frequently mounted and unmounted
+from the main board by developers depending whether debug serial is
+required or not.
+
+As the MAX3111 has no subvendor or product id registers available, the patch
+will try to access one register to decide if this IC is present or not.
+
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/mrst_max3110.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+--- a/drivers/serial/mrst_max3110.c
++++ b/drivers/serial/mrst_max3110.c
+@@ -721,7 +721,7 @@ static int serial_m3110_probe(struct spi
+ struct uart_max3110 *max;
+ int ret;
+ unsigned char *buffer;
+-
++ u16 res;
+ max = kzalloc(sizeof(*max), GFP_KERNEL);
+ if (!max)
+ return -ENOMEM;
+@@ -753,7 +753,16 @@ static int serial_m3110_probe(struct spi
+
+ max->cur_conf = 0;
+ atomic_set(&max->irq_pending, 0);
++ /* Check if reading configuration register returns something sane */
+
++ res = RC_TAG;
++ ret = max3110_write_then_read(max, (u8 *)&res, (u8 *)&res, 2, 0);
++ if (ret < 0 || res == 0 || res == 0xffff) {
++ printk(KERN_ERR "MAX3111 deemed not present (conf reg %04x)",
++ res);
++ ret = -ENODEV;
++ goto err_get_page;
++ }
+ buffer = (unsigned char *)__get_free_page(GFP_KERNEL);
+ if (!buffer) {
+ ret = -ENOMEM;
diff --git a/tty/mrst_max3110-add-uart-driver-for-max3110-on-moorestown.patch b/tty/mrst_max3110-add-uart-driver-for-max3110-on-moorestown.patch
new file mode 100644
index 00000000000000..011a3d5aa18780
--- /dev/null
+++ b/tty/mrst_max3110-add-uart-driver-for-max3110-on-moorestown.patch
@@ -0,0 +1,969 @@
+From alan@linux.intel.com Wed Jun 16 13:50:11 2010
+From: Alan Cox <alan@linux.intel.com>
+Date: Wed, 16 Jun 2010 14:46:09 +0100
+Subject: mrst_max3110: add UART driver for Max3110 on Moorestown
+To: greg@kroah.com, linux-serial@vger.kernel.org
+Message-ID: <20100616134554.12686.94694.stgit@localhost.localdomain>
+
+
+From: Feng Tang <feng.tang@intel.com>
+
+This driver enable the max3110 device, it can be used as
+a system console. the IRQ needs be enabled if user want a
+better performance. MRST max3110 works in 3.684MHz clock,
+which supports 230400 as its maximum rate.
+
+Signed-off-by: Feng Tang <feng.tang@intel.com>
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/serial/Kconfig | 17
+ drivers/serial/Makefile | 1
+ drivers/serial/mrst_max3110.c | 844 ++++++++++++++++++++++++++++++++++++++++++
+ drivers/serial/mrst_max3110.h | 59 ++
+ 4 files changed, 921 insertions(+)
+
+--- a/drivers/serial/Kconfig
++++ b/drivers/serial/Kconfig
+@@ -698,6 +698,23 @@ config SERIAL_SA1100_CONSOLE
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time.)
+
++config SERIAL_MRST_MAX3110
++ tristate "SPI UART driver for Max3110"
++ depends on SPI_DW_PCI
++ select SERIAL_CORE
++ select SERIAL_CORE_CONSOLE
++ help
++ This is the UART protocol driver for the MAX3110 device on
++ the Intel Moorestown platform. On other systems use the max3100
++ driver.
++
++config MRST_MAX3110_IRQ
++ boolean "Enable GPIO IRQ for Max3110 over Moorestown"
++ default n
++ depends on SERIAL_MRST_MAX3110 && GPIO_LANGWELL
++ help
++ This has to be enabled after Moorestown GPIO driver is loaded
++
+ config SERIAL_BFIN
+ tristate "Blackfin serial port support"
+ depends on BLACKFIN
+--- a/drivers/serial/Makefile
++++ b/drivers/serial/Makefile
+@@ -84,3 +84,4 @@ obj-$(CONFIG_SERIAL_TIMBERDALE) += timbu
+ obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
+ obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
+ obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
++obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o
+--- /dev/null
++++ b/drivers/serial/mrst_max3110.c
+@@ -0,0 +1,844 @@
++/*
++ * max3110.c - spi uart protocol driver for Maxim 3110 on Moorestown
++ *
++ * Copyright (C) Intel 2008 Feng Tang <feng.tang@intel.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope 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.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++/*
++ * Note:
++ * 1. From Max3110 spec, the Rx FIFO has 8 words, while the Tx FIFO only has
++ * 1 word. If SPI master controller doesn't support sclk frequency change,
++ * then the char need be sent out one by one with some delay
++ *
++ * 2. Currently only RX availabe interrrupt is used, no need for waiting TXE
++ * interrupt for a low speed UART device
++ */
++
++#include <linux/module.h>
++#include <linux/ioport.h>
++#include <linux/init.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++#include <linux/platform_device.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/serial_core.h>
++#include <linux/serial_reg.h>
++
++#include <linux/kthread.h>
++#include <linux/delay.h>
++#include <asm/atomic.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/dw_spi.h>
++
++#include "mrst_max3110.h"
++
++#define PR_FMT "mrst_max3110: "
++
++struct uart_max3110 {
++ struct uart_port port;
++ struct spi_device *spi;
++ char *name;
++
++ wait_queue_head_t wq;
++ struct task_struct *main_thread;
++ struct task_struct *read_thread;
++ int mthread_up;
++ spinlock_t lock;
++
++ u32 baud;
++ u16 cur_conf;
++ u8 clock;
++ u8 parity, word_7bits;
++
++ atomic_t uart_tx_need;
++
++ /* console related */
++ struct circ_buf con_xmit;
++ atomic_t con_tx_need;
++
++ /* irq related */
++ u16 irq;
++ atomic_t irq_pending;
++};
++
++/* global data structure, may need be removed */
++struct uart_max3110 *pmax;
++static inline void receive_char(struct uart_max3110 *max, u8 ch);
++static void receive_chars(struct uart_max3110 *max,
++ unsigned char *str, int len);
++static int max3110_read_multi(struct uart_max3110 *max, int len, u8 *buf);
++static void max3110_console_receive(struct uart_max3110 *max);
++
++int max3110_write_then_read(struct uart_max3110 *max,
++ const u8 *txbuf, u8 *rxbuf, unsigned len, int always_fast)
++{
++ struct spi_device *spi = max->spi;
++ struct spi_message message;
++ struct spi_transfer x;
++ int ret;
++
++ if (!txbuf || !rxbuf)
++ return -EINVAL;
++
++ spi_message_init(&message);
++ memset(&x, 0, sizeof x);
++ x.len = len;
++ x.tx_buf = txbuf;
++ x.rx_buf = rxbuf;
++ spi_message_add_tail(&x, &message);
++
++ if (always_fast)
++ x.speed_hz = 3125000;
++ else if (max->baud)
++ x.speed_hz = max->baud;
++
++ /* Do the i/o */
++ ret = spi_sync(spi, &message);
++ return ret;
++}
++
++/* Write a u16 to the device, and return one u16 read back */
++int max3110_out(struct uart_max3110 *max, const u16 out)
++{
++ u16 tmp;
++ int ret;
++
++ ret = max3110_write_then_read(max, (u8 *)&out, (u8 *)&tmp, 2, 1);
++ if (ret)
++ return ret;
++
++ /* If some valid data is read back */
++ if (tmp & MAX3110_READ_DATA_AVAILABLE)
++ receive_char(max, (tmp & 0xff));
++
++ return ret;
++}
++
++#define MAX_READ_LEN 20
++/*
++ * This is usually used to read data from SPIC RX FIFO, which doesn't
++ * need any delay like flushing character out. It returns how many
++ * valide bytes are read back
++ */
++static int max3110_read_multi(struct uart_max3110 *max, int len, u8 *buf)
++{
++ u16 out[MAX_READ_LEN], in[MAX_READ_LEN];
++ u8 *pbuf, valid_str[MAX_READ_LEN];
++ int i, j, bytelen;
++
++ if (len > MAX_READ_LEN) {
++ pr_err(PR_FMT "read len %d is too large\n", len);
++ return 0;
++ }
++
++ bytelen = len * 2;
++ memset(out, 0, bytelen);
++ memset(in, 0, bytelen);
++
++ if (max3110_write_then_read(max, (u8 *)out, (u8 *)in, bytelen, 1))
++ return 0;
++
++ /* If caller don't provide a buffer, then handle received char */
++ pbuf = buf ? buf : valid_str;
++
++ for (i = 0, j = 0; i < len; i++) {
++ if (in[i] & MAX3110_READ_DATA_AVAILABLE)
++ pbuf[j++] = (u8)(in[i] & 0xff);
++ }
++
++ if (j && (pbuf == valid_str))
++ receive_chars(max, valid_str, j);
++
++ return j;
++}
++
++static void serial_m3110_con_putchar(struct uart_port *port, int ch)
++{
++ struct uart_max3110 *max =
++ container_of(port, struct uart_max3110, port);
++ struct circ_buf *xmit = &max->con_xmit;
++
++ if (uart_circ_chars_free(xmit)) {
++ xmit->buf[xmit->head] = (char)ch;
++ xmit->head = (xmit->head + 1) & (PAGE_SIZE - 1);
++ }
++
++ if (!atomic_read(&max->con_tx_need)) {
++ atomic_set(&max->con_tx_need, 1);
++ wake_up_process(max->main_thread);
++ }
++}
++
++/*
++ * Print a string to the serial port trying not to disturb
++ * any possible real use of the port...
++ *
++ * The console_lock must be held when we get here.
++ */
++static void serial_m3110_con_write(struct console *co,
++ const char *s, unsigned int count)
++{
++ if (!pmax)
++ return;
++
++ uart_console_write(&pmax->port, s, count, serial_m3110_con_putchar);
++}
++
++static int __init
++serial_m3110_con_setup(struct console *co, char *options)
++{
++ struct uart_max3110 *max = pmax;
++ int baud = 115200;
++ int bits = 8;
++ int parity = 'n';
++ int flow = 'n';
++
++ pr_info(PR_FMT "setting up console\n");
++
++ if (!max) {
++ pr_err(PR_FMT "pmax is NULL, return");
++ return -ENODEV;
++ }
++
++ if (options)
++ uart_parse_options(options, &baud, &parity, &bits, &flow);
++
++ return uart_set_options(&max->port, co, baud, parity, bits, flow);
++}
++
++static struct tty_driver *serial_m3110_con_device(struct console *co,
++ int *index)
++{
++ struct uart_driver *p = co->data;
++ *index = co->index;
++ return p->tty_driver;
++}
++
++static struct uart_driver serial_m3110_reg;
++static struct console serial_m3110_console = {
++ .name = "ttyS",
++ .write = serial_m3110_con_write,
++ .device = serial_m3110_con_device,
++ .setup = serial_m3110_con_setup,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++ .data = &serial_m3110_reg,
++};
++
++#define MRST_CONSOLE (&serial_m3110_console)
++
++static unsigned int serial_m3110_tx_empty(struct uart_port *port)
++{
++ return 1;
++}
++
++static void serial_m3110_stop_tx(struct uart_port *port)
++{
++ return;
++}
++
++/* stop_rx will be called in spin_lock env */
++static void serial_m3110_stop_rx(struct uart_port *port)
++{
++ return;
++}
++
++#define WORDS_PER_XFER 128
++static inline void send_circ_buf(struct uart_max3110 *max,
++ struct circ_buf *xmit)
++{
++ int len, left = 0;
++ u16 obuf[WORDS_PER_XFER], ibuf[WORDS_PER_XFER];
++ u8 valid_str[WORDS_PER_XFER];
++ int i, j;
++
++ while (!uart_circ_empty(xmit)) {
++ left = uart_circ_chars_pending(xmit);
++ while (left) {
++ len = (left >= WORDS_PER_XFER) ? WORDS_PER_XFER : left;
++
++ memset(obuf, 0, len * 2);
++ memset(ibuf, 0, len * 2);
++ for (i = 0; i < len; i++) {
++ obuf[i] = (u8)xmit->buf[xmit->tail] | WD_TAG;
++ xmit->tail = (xmit->tail + 1) &
++ (UART_XMIT_SIZE - 1);
++ }
++ max3110_write_then_read(max, (u8 *)obuf,
++ (u8 *)ibuf, len * 2, 0);
++
++ for (i = 0, j = 0; i < len; i++) {
++ if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
++ valid_str[j++] = (u8)(ibuf[i] & 0xff);
++ }
++
++ if (j)
++ receive_chars(max, valid_str, j);
++
++ max->port.icount.tx += len;
++ left -= len;
++ }
++ }
++}
++
++static void transmit_char(struct uart_max3110 *max)
++{
++ struct uart_port *port = &max->port;
++ struct circ_buf *xmit = &port->state->xmit;
++
++ if (uart_circ_empty(xmit) || uart_tx_stopped(port))
++ return;
++
++ send_circ_buf(max, xmit);
++
++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++ uart_write_wakeup(port);
++
++ if (uart_circ_empty(xmit))
++ serial_m3110_stop_tx(port);
++}
++
++/* This will be called by uart_write() and tty_write, can't
++ * go to sleep */
++static void serial_m3110_start_tx(struct uart_port *port)
++{
++ struct uart_max3110 *max =
++ container_of(port, struct uart_max3110, port);
++
++ if (!atomic_read(&max->uart_tx_need)) {
++ atomic_set(&max->uart_tx_need, 1);
++ wake_up_process(max->main_thread);
++ }
++}
++
++static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len)
++{
++ struct uart_port *port = &max->port;
++ struct tty_struct *tty;
++ int usable;
++
++ /* If uart is not opened, just return */
++ if (!port->state)
++ return;
++
++ tty = port->state->port.tty;
++ if (!tty)
++ return; /* receive some char before the tty is opened */
++
++ while (len) {
++ usable = tty_buffer_request_room(tty, len);
++ if (usable) {
++ tty_insert_flip_string(tty, str, usable);
++ str += usable;
++ port->icount.rx += usable;
++ tty_flip_buffer_push(tty);
++ }
++ len -= usable;
++ }
++}
++
++static inline void receive_char(struct uart_max3110 *max, u8 ch)
++{
++ receive_chars(max, &ch, 1);
++}
++
++static void max3110_console_receive(struct uart_max3110 *max)
++{
++ int loop = 1, num, total = 0;
++ u8 recv_buf[512], *pbuf;
++
++ pbuf = recv_buf;
++ do {
++ num = max3110_read_multi(max, 8, pbuf);
++
++ if (num) {
++ loop = 10;
++ pbuf += num;
++ total += num;
++
++ if (total >= 500) {
++ receive_chars(max, recv_buf, total);
++ pbuf = recv_buf;
++ total = 0;
++ }
++ }
++ } while (--loop);
++
++ if (total)
++ receive_chars(max, recv_buf, total);
++}
++
++static int max3110_main_thread(void *_max)
++{
++ struct uart_max3110 *max = _max;
++ wait_queue_head_t *wq = &max->wq;
++ int ret = 0;
++ struct circ_buf *xmit = &max->con_xmit;
++
++ init_waitqueue_head(wq);
++ pr_info(PR_FMT "start main thread\n");
++
++ do {
++ wait_event_interruptible(*wq, (atomic_read(&max->irq_pending) ||
++ atomic_read(&max->con_tx_need) ||
++ atomic_read(&max->uart_tx_need)) ||
++ kthread_should_stop());
++ max->mthread_up = 1;
++
++#ifdef CONFIG_MRST_MAX3110_IRQ
++ if (atomic_read(&max->irq_pending)) {
++ max3110_console_receive(max);
++ atomic_set(&max->irq_pending, 0);
++ }
++#endif
++
++ /* first handle console output */
++ if (atomic_read(&max->con_tx_need)) {
++ send_circ_buf(max, xmit);
++ atomic_set(&max->con_tx_need, 0);
++ }
++
++ /* handle uart output */
++ if (atomic_read(&max->uart_tx_need)) {
++ transmit_char(max);
++ atomic_set(&max->uart_tx_need, 0);
++ }
++ max->mthread_up = 0;
++ } while (!kthread_should_stop());
++
++ return ret;
++}
++
++#ifdef CONFIG_MRST_MAX3110_IRQ
++static irqreturn_t serial_m3110_irq(int irq, void *dev_id)
++{
++ struct uart_max3110 *max = dev_id;
++
++ /* max3110's irq is a falling edge, not level triggered,
++ * so no need to disable the irq */
++ if (!atomic_read(&max->irq_pending)) {
++ atomic_inc(&max->irq_pending);
++ wake_up_process(max->main_thread);
++ }
++ return IRQ_HANDLED;
++}
++#else
++/* if don't use RX IRQ, then need a thread to polling read */
++static int max3110_read_thread(void *_max)
++{
++ struct uart_max3110 *max = _max;
++
++ pr_info(PR_FMT "start read thread\n");
++ do {
++ if (!max->mthread_up)
++ max3110_console_receive(max);
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(HZ / 20);
++ } while (!kthread_should_stop());
++
++ return 0;
++}
++#endif
++
++static int serial_m3110_startup(struct uart_port *port)
++{
++ struct uart_max3110 *max =
++ container_of(port, struct uart_max3110, port);
++ u16 config = 0;
++ int ret = 0;
++
++ if (port->line != 0)
++ pr_err(PR_FMT "uart port startup failed\n");
++
++ /* firstly disable all IRQ and config it to 115200, 8n1 */
++ config = WC_TAG | WC_FIFO_ENABLE
++ | WC_1_STOPBITS
++ | WC_8BIT_WORD
++ | WC_BAUD_DR2;
++ ret = max3110_out(max, config);
++
++ /* as we use thread to handle tx/rx, need set low latency */
++ port->state->port.tty->low_latency = 1;
++
++#ifdef CONFIG_MRST_MAX3110_IRQ
++ ret = request_irq(max->irq, serial_m3110_irq,
++ IRQ_TYPE_EDGE_FALLING, "max3110", max);
++ if (ret)
++ return ret;
++
++ /* enable RX IRQ only */
++ config |= WC_RXA_IRQ_ENABLE;
++ max3110_out(max, config);
++#else
++ /* if IRQ is disabled, start a read thread for input data */
++ max->read_thread =
++ kthread_run(max3110_read_thread, max, "max3110_read");
++#endif
++
++ max->cur_conf = config;
++ return 0;
++}
++
++static void serial_m3110_shutdown(struct uart_port *port)
++{
++ struct uart_max3110 *max =
++ container_of(port, struct uart_max3110, port);
++ u16 config;
++
++ if (max->read_thread) {
++ kthread_stop(max->read_thread);
++ max->read_thread = NULL;
++ }
++
++#ifdef CONFIG_MRST_MAX3110_IRQ
++ free_irq(max->irq, max);
++#endif
++
++ /* Disable interrupts from this port */
++ config = WC_TAG | WC_SW_SHDI;
++ max3110_out(max, config);
++}
++
++static void serial_m3110_release_port(struct uart_port *port)
++{
++}
++
++static int serial_m3110_request_port(struct uart_port *port)
++{
++ return 0;
++}
++
++static void serial_m3110_config_port(struct uart_port *port, int flags)
++{
++ /* give it fake type */
++ port->type = PORT_PXA;
++}
++
++static int
++serial_m3110_verify_port(struct uart_port *port, struct serial_struct *ser)
++{
++ /* we don't want the core code to modify any port params */
++ return -EINVAL;
++}
++
++
++static const char *serial_m3110_type(struct uart_port *port)
++{
++ struct uart_max3110 *max =
++ container_of(port, struct uart_max3110, port);
++ return max->name;
++}
++
++static void
++serial_m3110_set_termios(struct uart_port *port, struct ktermios *termios,
++ struct ktermios *old)
++{
++ struct uart_max3110 *max =
++ container_of(port, struct uart_max3110, port);
++ unsigned char cval;
++ unsigned int baud, parity = 0;
++ int clk_div = -1;
++ u16 new_conf = max->cur_conf;
++
++ switch (termios->c_cflag & CSIZE) {
++ case CS7:
++ cval = UART_LCR_WLEN7;
++ new_conf |= WC_7BIT_WORD;
++ break;
++ default:
++ case CS8:
++ cval = UART_LCR_WLEN8;
++ new_conf |= WC_8BIT_WORD;
++ break;
++ }
++
++ baud = uart_get_baud_rate(port, termios, old, 0, 230400);
++
++ /* first calc the div for 1.8MHZ clock case */
++ switch (baud) {
++ case 300:
++ clk_div = WC_BAUD_DR384;
++ break;
++ case 600:
++ clk_div = WC_BAUD_DR192;
++ break;
++ case 1200:
++ clk_div = WC_BAUD_DR96;
++ break;
++ case 2400:
++ clk_div = WC_BAUD_DR48;
++ break;
++ case 4800:
++ clk_div = WC_BAUD_DR24;
++ break;
++ case 9600:
++ clk_div = WC_BAUD_DR12;
++ break;
++ case 19200:
++ clk_div = WC_BAUD_DR6;
++ break;
++ case 38400:
++ clk_div = WC_BAUD_DR3;
++ break;
++ case 57600:
++ clk_div = WC_BAUD_DR2;
++ break;
++ case 115200:
++ clk_div = WC_BAUD_DR1;
++ break;
++ case 230400:
++ if (max->clock & MAX3110_HIGH_CLK)
++ break;
++ default:
++ /* pick the previous baud rate */
++ baud = max->baud;
++ clk_div = max->cur_conf & WC_BAUD_DIV_MASK;
++ tty_termios_encode_baud_rate(termios, baud, baud);
++ }
++
++ if (max->clock & MAX3110_HIGH_CLK) {
++ clk_div += 1;
++ /* high clk version max3110 doesn't support B300 */
++ if (baud == 300)
++ baud = 600;
++ if (baud == 230400)
++ clk_div = WC_BAUD_DR1;
++ tty_termios_encode_baud_rate(termios, baud, baud);
++ }
++
++ new_conf = (new_conf & ~WC_BAUD_DIV_MASK) | clk_div;
++ if (termios->c_cflag & CSTOPB)
++ new_conf |= WC_2_STOPBITS;
++ else
++ new_conf &= ~WC_2_STOPBITS;
++
++ if (termios->c_cflag & PARENB) {
++ new_conf |= WC_PARITY_ENABLE;
++ parity |= UART_LCR_PARITY;
++ } else
++ new_conf &= ~WC_PARITY_ENABLE;
++
++ if (!(termios->c_cflag & PARODD))
++ parity |= UART_LCR_EPAR;
++ max->parity = parity;
++
++ uart_update_timeout(port, termios->c_cflag, baud);
++
++ new_conf |= WC_TAG;
++ if (new_conf != max->cur_conf) {
++ max3110_out(max, new_conf);
++ max->cur_conf = new_conf;
++ max->baud = baud;
++ }
++}
++
++/* don't handle hw handshaking */
++static unsigned int serial_m3110_get_mctrl(struct uart_port *port)
++{
++ return TIOCM_DSR | TIOCM_CAR | TIOCM_DSR;
++}
++
++static void serial_m3110_set_mctrl(struct uart_port *port, unsigned int mctrl)
++{
++}
++
++static void serial_m3110_break_ctl(struct uart_port *port, int break_state)
++{
++}
++
++static void serial_m3110_pm(struct uart_port *port, unsigned int state,
++ unsigned int oldstate)
++{
++}
++
++static void serial_m3110_enable_ms(struct uart_port *port)
++{
++}
++
++struct uart_ops serial_m3110_ops = {
++ .tx_empty = serial_m3110_tx_empty,
++ .set_mctrl = serial_m3110_set_mctrl,
++ .get_mctrl = serial_m3110_get_mctrl,
++ .stop_tx = serial_m3110_stop_tx,
++ .start_tx = serial_m3110_start_tx,
++ .stop_rx = serial_m3110_stop_rx,
++ .enable_ms = serial_m3110_enable_ms,
++ .break_ctl = serial_m3110_break_ctl,
++ .startup = serial_m3110_startup,
++ .shutdown = serial_m3110_shutdown,
++ .set_termios = serial_m3110_set_termios, /* must have */
++ .pm = serial_m3110_pm,
++ .type = serial_m3110_type,
++ .release_port = serial_m3110_release_port,
++ .request_port = serial_m3110_request_port,
++ .config_port = serial_m3110_config_port,
++ .verify_port = serial_m3110_verify_port,
++};
++
++static struct uart_driver serial_m3110_reg = {
++ .owner = THIS_MODULE,
++ .driver_name = "MRST serial",
++ .dev_name = "ttyS",
++ .major = TTY_MAJOR,
++ .minor = 64,
++ .nr = 1,
++ .cons = MRST_CONSOLE,
++};
++
++static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state)
++{
++ return 0;
++}
++
++static int serial_m3110_resume(struct spi_device *spi)
++{
++ return 0;
++}
++
++static struct dw_spi_chip spi0_uart = {
++ .poll_mode = 1,
++ .enable_dma = 0,
++ .type = SPI_FRF_SPI,
++};
++
++static int serial_m3110_probe(struct spi_device *spi)
++{
++ struct uart_max3110 *max;
++ int ret;
++ unsigned char *buffer;
++
++ max = kzalloc(sizeof(*max), GFP_KERNEL);
++ if (!max)
++ return -ENOMEM;
++
++ /* set spi info */
++ spi->mode = SPI_MODE_0;
++ spi->bits_per_word = 16;
++ max->clock = MAX3110_HIGH_CLK;
++ spi->controller_data = &spi0_uart;
++
++ spi_setup(spi);
++
++ max->port.type = PORT_PXA; /* need apply for a max3110 type */
++ max->port.fifosize = 2; /* only have 16b buffer */
++ max->port.ops = &serial_m3110_ops;
++ max->port.line = 0;
++ max->port.dev = &spi->dev;
++ max->port.uartclk = 115200;
++
++ max->spi = spi;
++ max->name = spi->modalias; /* use spi name as the name */
++ max->irq = (u16)spi->irq;
++
++ spin_lock_init(&max->lock);
++
++ max->word_7bits = 0;
++ max->parity = 0;
++ max->baud = 0;
++
++ max->cur_conf = 0;
++ atomic_set(&max->irq_pending, 0);
++
++ buffer = (unsigned char *)__get_free_page(GFP_KERNEL);
++ if (!buffer) {
++ ret = -ENOMEM;
++ goto err_get_page;
++ }
++ max->con_xmit.buf = (unsigned char *)buffer;
++ max->con_xmit.head = max->con_xmit.tail = 0;
++
++ max->main_thread = kthread_run(max3110_main_thread,
++ max, "max3110_main");
++ if (IS_ERR(max->main_thread)) {
++ ret = PTR_ERR(max->main_thread);
++ goto err_kthread;
++ }
++
++ pmax = max;
++ /* give membase a psudo value to pass serial_core's check */
++ max->port.membase = (void *)0xff110000;
++ uart_add_one_port(&serial_m3110_reg, &max->port);
++
++ return 0;
++
++err_kthread:
++ free_page((unsigned long)buffer);
++err_get_page:
++ pmax = NULL;
++ kfree(max);
++ return ret;
++}
++
++static int max3110_remove(struct spi_device *dev)
++{
++ struct uart_max3110 *max = pmax;
++
++ if (!pmax)
++ return 0;
++
++ pmax = NULL;
++ uart_remove_one_port(&serial_m3110_reg, &max->port);
++
++ free_page((unsigned long)max->con_xmit.buf);
++
++ if (max->main_thread)
++ kthread_stop(max->main_thread);
++
++ kfree(max);
++ return 0;
++}
++
++static struct spi_driver uart_max3110_driver = {
++ .driver = {
++ .name = "spi_max3111",
++ .bus = &spi_bus_type,
++ .owner = THIS_MODULE,
++ },
++ .probe = serial_m3110_probe,
++ .remove = __devexit_p(max3110_remove),
++ .suspend = serial_m3110_suspend,
++ .resume = serial_m3110_resume,
++};
++
++
++int __init serial_m3110_init(void)
++{
++ int ret = 0;
++
++ ret = uart_register_driver(&serial_m3110_reg);
++ if (ret)
++ return ret;
++
++ ret = spi_register_driver(&uart_max3110_driver);
++ if (ret)
++ uart_unregister_driver(&serial_m3110_reg);
++
++ return ret;
++}
++
++void __exit serial_m3110_exit(void)
++{
++ spi_unregister_driver(&uart_max3110_driver);
++ uart_unregister_driver(&serial_m3110_reg);
++}
++
++module_init(serial_m3110_init);
++module_exit(serial_m3110_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("max3110-uart");
+--- /dev/null
++++ b/drivers/serial/mrst_max3110.h
+@@ -0,0 +1,59 @@
++#ifndef _MRST_MAX3110_H
++#define _MRST_MAX3110_H
++
++#define MAX3110_HIGH_CLK 0x1 /* 3.6864 MHZ */
++#define MAX3110_LOW_CLK 0x0 /* 1.8432 MHZ */
++
++/* status bits for all 4 MAX3110 operate modes */
++#define MAX3110_READ_DATA_AVAILABLE (1 << 15)
++#define MAX3110_WRITE_BUF_EMPTY (1 << 14)
++
++#define WC_TAG (3 << 14)
++#define RC_TAG (1 << 14)
++#define WD_TAG (2 << 14)
++#define RD_TAG (0 << 14)
++
++/* bits def for write configuration */
++#define WC_FIFO_ENABLE_MASK (1 << 13)
++#define WC_FIFO_ENABLE (0 << 13)
++
++#define WC_SW_SHDI (1 << 12)
++
++#define WC_IRQ_MASK (0xF << 8)
++#define WC_TXE_IRQ_ENABLE (1 << 11) /* TX empty irq */
++#define WC_RXA_IRQ_ENABLE (1 << 10) /* RX availabe irq */
++#define WC_PAR_HIGH_IRQ_ENABLE (1 << 9)
++#define WC_REC_ACT_IRQ_ENABLE (1 << 8)
++
++#define WC_IRDA_ENABLE (1 << 7)
++
++#define WC_STOPBITS_MASK (1 << 6)
++#define WC_2_STOPBITS (1 << 6)
++#define WC_1_STOPBITS (0 << 6)
++
++#define WC_PARITY_ENABLE_MASK (1 << 5)
++#define WC_PARITY_ENABLE (1 << 5)
++
++#define WC_WORDLEN_MASK (1 << 4)
++#define WC_7BIT_WORD (1 << 4)
++#define WC_8BIT_WORD (0 << 4)
++
++#define WC_BAUD_DIV_MASK (0xF)
++#define WC_BAUD_DR1 (0x0)
++#define WC_BAUD_DR2 (0x1)
++#define WC_BAUD_DR4 (0x2)
++#define WC_BAUD_DR8 (0x3)
++#define WC_BAUD_DR16 (0x4)
++#define WC_BAUD_DR32 (0x5)
++#define WC_BAUD_DR64 (0x6)
++#define WC_BAUD_DR128 (0x7)
++#define WC_BAUD_DR3 (0x8)
++#define WC_BAUD_DR6 (0x9)
++#define WC_BAUD_DR12 (0xA)
++#define WC_BAUD_DR24 (0xB)
++#define WC_BAUD_DR48 (0xC)
++#define WC_BAUD_DR96 (0xD)
++#define WC_BAUD_DR192 (0xE)
++#define WC_BAUD_DR384 (0xF)
++
++#endif
diff --git a/tty/serial-add-port-helpers.patch b/tty/serial-add-port-helpers.patch
new file mode 100644
index 00000000000000..3c849d8b6c6a18
--- /dev/null
+++ b/tty/serial-add-port-helpers.patch
@@ -0,0 +1,117 @@
+From arnd@arndb.de Wed Jun 16 13:35:51 2010
+From: Alan Cox <alan@linux.intel.com>
+Date: Tue, 1 Jun 2010 22:52:58 +0200
+Subject: serial: add port helpers
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>, Alan Cox <alan@linux.intel.com>
+Message-ID: <1275425591-8803-19-git-send-email-arnd@arndb.de>
+
+
+From: Alan Cox <alan@linux.intel.com>
+
+We can make this the same as the ones that will be needed by the tty_port
+helper logic that we want to move to but still call them from the existing
+code base.
+
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/serial_core.c | 51 +++++++++++++++++++++++++++++++------------
+ 1 file changed, 37 insertions(+), 14 deletions(-)
+
+--- a/drivers/serial/serial_core.c
++++ b/drivers/serial/serial_core.c
+@@ -1501,6 +1501,34 @@ static void uart_update_termios(struct t
+ }
+ }
+
++static int uart_carrier_raised(struct tty_port *port)
++{
++ struct uart_state *state = container_of(port, struct uart_state, port);
++ struct uart_port *uport = state->uart_port;
++ int mctrl;
++ mutex_lock(&port->mutex);
++ spin_lock_irq(&uport->lock);
++ uport->ops->enable_ms(uport);
++ mctrl = uport->ops->get_mctrl(uport);
++ spin_unlock_irq(&uport->lock);
++ mutex_unlock(&port->mutex);
++ if (mctrl & TIOCM_CAR)
++ return 1;
++ return 0;
++}
++
++static void uart_dtr_rts(struct tty_port *port, int onoff)
++{
++ struct uart_state *state = container_of(port, struct uart_state, port);
++ struct uart_port *uport = state->uart_port;
++ mutex_lock(&port->mutex);
++ if (onoff)
++ uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
++ else
++ uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
++ mutex_unlock(&port->mutex);
++}
++
+ /*
+ * Block the open until the port is ready. We must be called with
+ * the per-port semaphore held.
+@@ -1509,9 +1537,7 @@ static int
+ uart_block_til_ready(struct file *filp, struct uart_state *state)
+ {
+ DECLARE_WAITQUEUE(wait, current);
+- struct uart_port *uport = state->uart_port;
+ struct tty_port *port = &state->port;
+- unsigned int mctrl;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+@@ -1555,23 +1581,14 @@ uart_block_til_ready(struct file *filp,
+ * not set RTS here - we want to make sure we catch
+ * the data from the modem.
+ */
+- if (port->tty->termios->c_cflag & CBAUD) {
+- mutex_lock(&port->mutex);
+- uart_set_mctrl(uport, TIOCM_DTR);
+- mutex_unlock(&port->mutex);
+- }
++ if (port->tty->termios->c_cflag & CBAUD)
++ tty_port_raise_dtr_rts(port);
+
+ /*
+ * and wait for the carrier to indicate that the
+ * modem is ready for us.
+ */
+- mutex_lock(&port->mutex);
+- spin_lock_irq(&uport->lock);
+- uport->ops->enable_ms(uport);
+- mctrl = uport->ops->get_mctrl(uport);
+- spin_unlock_irq(&uport->lock);
+- mutex_unlock(&port->mutex);
+- if (mctrl & TIOCM_CAR)
++ if (tty_port_carrier_raised(port))
+ break;
+
+ schedule();
+@@ -2349,6 +2366,11 @@ static const struct tty_operations uart_
+ #endif
+ };
+
++static const struct tty_port_operations uart_port_ops = {
++ .carrier_raised = uart_carrier_raised,
++ .dtr_rts = uart_dtr_rts,
++};
++
+ /**
+ * uart_register_driver - register a driver with the uart core layer
+ * @drv: low level driver structure
+@@ -2405,6 +2427,7 @@ int uart_register_driver(struct uart_dri
+ struct tty_port *port = &state->port;
+
+ tty_port_init(port);
++ port->ops = &uart_port_ops;
+ port->close_delay = 500; /* .5 seconds */
+ port->closing_wait = 30000; /* 30 seconds */
+ tasklet_init(&state->tlet, uart_tasklet_action,
diff --git a/tty/serial-add-uart_cap_efr-and-uart_cap_sleep-flags-to-16c950-uarts-definition.patch b/tty/serial-add-uart_cap_efr-and-uart_cap_sleep-flags-to-16c950-uarts-definition.patch
new file mode 100644
index 00000000000000..86907075767144
--- /dev/null
+++ b/tty/serial-add-uart_cap_efr-and-uart_cap_sleep-flags-to-16c950-uarts-definition.patch
@@ -0,0 +1,33 @@
+From yegor_sub1@visionsystems.de Wed Jun 16 13:49:47 2010
+From: Yegor Yefremov <yegor_sub1@visionsystems.de>
+Date: Wed, 16 Jun 2010 16:29:55 +0200
+Subject: serial: add UART_CAP_EFR and UART_CAP_SLEEP flags to 16C950 UARTs definition
+To: linux-serial@vger.kernel.org
+Cc: Greg KH <greg@kroah.com>
+Message-ID: <4C18DFE3.2030109@visionsystems.de>
+
+
+Adding UART_CAP_EFR and UART_CAP_SLEEP flags will enable sleep mode
+and automatic CTS flow control for 16C950 UARTs. It will also avoid
+capabilities detection warning like this:
+
+"ttyS0: detected caps 00000700 should be 00000100"
+
+Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/8250.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/serial/8250.c
++++ b/drivers/serial/8250.c
+@@ -241,7 +241,7 @@ static const struct serial8250_config ua
+ .fifo_size = 128,
+ .tx_loadsz = 128,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+- .flags = UART_CAP_FIFO,
++ .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
+ },
+ [PORT_16654] = {
+ .name = "ST16654",
diff --git a/tty/serial-change-the-wait-for-carrier-locking.patch b/tty/serial-change-the-wait-for-carrier-locking.patch
new file mode 100644
index 00000000000000..9ec2e928168bac
--- /dev/null
+++ b/tty/serial-change-the-wait-for-carrier-locking.patch
@@ -0,0 +1,184 @@
+From arnd@arndb.de Wed Jun 16 13:35:17 2010
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Tue, 1 Jun 2010 22:52:57 +0200
+Subject: serial: Change the wait for carrier locking
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>, Alan Cox <alan@linux.intel.com>
+Message-ID: <1275425591-8803-18-git-send-email-arnd@arndb.de>
+
+
+From: Alan Cox <alan@linux.intel.com>
+
+We want to push the lock/unlock into the helper functions so that we
+can prepare to move to using the tty_port helper. The expansion initially
+comes out a bit ugly but its worth the temporary expansion IMHO just so
+we can produce a nice testable series of changes.
+
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/serial_core.c | 44 ++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 35 insertions(+), 9 deletions(-)
+
+--- a/drivers/serial/serial_core.c
++++ b/drivers/serial/serial_core.c
+@@ -1272,6 +1272,7 @@ static void uart_close(struct tty_struct
+ struct uart_state *state = tty->driver_data;
+ struct tty_port *port;
+ struct uart_port *uport;
++ unsigned long flags;
+
+ BUG_ON(!kernel_locked());
+
+@@ -1284,9 +1285,12 @@ static void uart_close(struct tty_struct
+ pr_debug("uart_close(%d) called\n", uport->line);
+
+ mutex_lock(&port->mutex);
++ spin_lock_irqsave(&port->lock, flags);
+
+- if (tty_hung_up_p(filp))
++ if (tty_hung_up_p(filp)) {
++ spin_unlock_irqrestore(&port->lock, flags);
+ goto done;
++ }
+
+ if ((tty->count == 1) && (port->count != 1)) {
+ /*
+@@ -1305,8 +1309,10 @@ static void uart_close(struct tty_struct
+ tty->name, port->count);
+ port->count = 0;
+ }
+- if (port->count)
++ if (port->count) {
++ spin_unlock_irqrestore(&port->lock, flags);
+ goto done;
++ }
+
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+@@ -1314,6 +1320,7 @@ static void uart_close(struct tty_struct
+ * setting tty->closing.
+ */
+ tty->closing = 1;
++ spin_unlock_irqrestore(&port->lock, flags);
+
+ if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, msecs_to_jiffies(port->closing_wait));
+@@ -1340,20 +1347,26 @@ static void uart_close(struct tty_struct
+
+ tty_ldisc_flush(tty);
+
+- tty->closing = 0;
+ tty_port_tty_set(port, NULL);
++ spin_lock_irqsave(&port->lock, flags);
++ tty->closing = 0;
+
+ if (port->blocked_open) {
++ spin_unlock_irqrestore(&port->lock, flags);
+ if (port->close_delay)
+ msleep_interruptible(port->close_delay);
++ spin_lock_irqsave(&port->lock, flags);
+ } else if (!uart_console(uport)) {
++ spin_unlock_irqrestore(&port->lock, flags);
+ uart_change_pm(state, 3);
++ spin_lock_irqsave(&port->lock, flags);
+ }
+
+ /*
+ * Wake up anyone trying to open this port.
+ */
+ clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
++ spin_unlock_irqrestore(&port->lock, flags);
+ wake_up_interruptible(&port->open_wait);
+
+ done:
+@@ -1429,6 +1442,7 @@ static void uart_hangup(struct tty_struc
+ {
+ struct uart_state *state = tty->driver_data;
+ struct tty_port *port = &state->port;
++ unsigned long flags;
+
+ BUG_ON(!kernel_locked());
+ pr_debug("uart_hangup(%d)\n", state->uart_port->line);
+@@ -1437,8 +1451,10 @@ static void uart_hangup(struct tty_struc
+ if (port->flags & ASYNC_NORMAL_ACTIVE) {
+ uart_flush_buffer(tty);
+ uart_shutdown(tty, state);
++ spin_lock_irqsave(&port->lock, flags);
+ port->count = 0;
+ clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
++ spin_unlock_irqrestore(&port->lock, flags);
+ tty_port_tty_set(port, NULL);
+ wake_up_interruptible(&port->open_wait);
+ wake_up_interruptible(&port->delta_msr_wait);
+@@ -1496,9 +1512,13 @@ uart_block_til_ready(struct file *filp,
+ struct uart_port *uport = state->uart_port;
+ struct tty_port *port = &state->port;
+ unsigned int mctrl;
++ unsigned long flags;
+
++ spin_lock_irqsave(&port->lock, flags);
++ if (!tty_hung_up_p(filp))
++ port->count--;
+ port->blocked_open++;
+- port->count--;
++ spin_unlock_irqrestore(&port->lock, flags);
+
+ add_wait_queue(&port->open_wait, &wait);
+ while (1) {
+@@ -1535,23 +1555,26 @@ uart_block_til_ready(struct file *filp,
+ * not set RTS here - we want to make sure we catch
+ * the data from the modem.
+ */
+- if (port->tty->termios->c_cflag & CBAUD)
++ if (port->tty->termios->c_cflag & CBAUD) {
++ mutex_lock(&port->mutex);
+ uart_set_mctrl(uport, TIOCM_DTR);
++ mutex_unlock(&port->mutex);
++ }
+
+ /*
+ * and wait for the carrier to indicate that the
+ * modem is ready for us.
+ */
++ mutex_lock(&port->mutex);
+ spin_lock_irq(&uport->lock);
+ uport->ops->enable_ms(uport);
+ mctrl = uport->ops->get_mctrl(uport);
+ spin_unlock_irq(&uport->lock);
++ mutex_unlock(&port->mutex);
+ if (mctrl & TIOCM_CAR)
+ break;
+
+- mutex_unlock(&port->mutex);
+ schedule();
+- mutex_lock(&port->mutex);
+
+ if (signal_pending(current))
+ break;
+@@ -1559,8 +1582,11 @@ uart_block_til_ready(struct file *filp,
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&port->open_wait, &wait);
+
+- port->count++;
++ spin_lock_irqsave(&port->lock, flags);
++ if (!tty_hung_up_p(filp))
++ port->count++;
+ port->blocked_open--;
++ spin_unlock_irqrestore(&port->lock, flags);
+
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+@@ -1677,9 +1703,9 @@ static int uart_open(struct tty_struct *
+ /*
+ * If we succeeded, wait until the port is ready.
+ */
++ mutex_unlock(&port->mutex);
+ if (retval == 0)
+ retval = uart_block_til_ready(filp, state);
+- mutex_unlock(&port->mutex);
+
+ /*
+ * If this is the first open to succeed, adjust things to suit.
diff --git a/tty/serial-trim-locking-on-the-helpers.patch b/tty/serial-trim-locking-on-the-helpers.patch
new file mode 100644
index 00000000000000..9f0337a4500478
--- /dev/null
+++ b/tty/serial-trim-locking-on-the-helpers.patch
@@ -0,0 +1,54 @@
+From arnd@arndb.de Wed Jun 16 13:36:19 2010
+From: Alan Cox <alan@linux.intel.com>
+Date: Tue, 1 Jun 2010 22:52:59 +0200
+Subject: serial: trim locking on the helpers
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>, Alan Cox <alan@linux.intel.com>
+Message-ID: <1275425591-8803-20-git-send-email-arnd@arndb.de>
+
+
+From: Alan Cox <alan@linux.intel.com>
+
+The port mutex protects port->tty, but these paths never need to walk from
+port->tty. They do need the low level lock as the API expects that but they
+already also take it.
+
+Thus we can drop the extra mutex lock calls here.
+
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/serial_core.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+--- a/drivers/serial/serial_core.c
++++ b/drivers/serial/serial_core.c
+@@ -1506,12 +1506,10 @@ static int uart_carrier_raised(struct tt
+ struct uart_state *state = container_of(port, struct uart_state, port);
+ struct uart_port *uport = state->uart_port;
+ int mctrl;
+- mutex_lock(&port->mutex);
+ spin_lock_irq(&uport->lock);
+ uport->ops->enable_ms(uport);
+ mctrl = uport->ops->get_mctrl(uport);
+ spin_unlock_irq(&uport->lock);
+- mutex_unlock(&port->mutex);
+ if (mctrl & TIOCM_CAR)
+ return 1;
+ return 0;
+@@ -1521,12 +1519,11 @@ static void uart_dtr_rts(struct tty_port
+ {
+ struct uart_state *state = container_of(port, struct uart_state, port);
+ struct uart_port *uport = state->uart_port;
+- mutex_lock(&port->mutex);
++
+ if (onoff)
+ uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
+ else
+ uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
+- mutex_unlock(&port->mutex);
+ }
+
+ /*
diff --git a/tty/serial-use-block_til_ready-helper.patch b/tty/serial-use-block_til_ready-helper.patch
new file mode 100644
index 00000000000000..a87944d7935e9e
--- /dev/null
+++ b/tty/serial-use-block_til_ready-helper.patch
@@ -0,0 +1,124 @@
+From arnd@arndb.de Wed Jun 16 13:36:52 2010
+From: Alan Cox <alan@linux.intel.com>
+Date: Tue, 1 Jun 2010 22:53:00 +0200
+Subject: serial: Use block_til_ready helper
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>, Alan Cox <alan@linux.intel.com>
+Message-ID: <1275425591-8803-21-git-send-email-arnd@arndb.de>
+
+
+From: Alan Cox <alan@linux.intel.com>
+
+Our code now rather closely resembles the helper, so switch to it.
+
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/serial_core.c | 87 -------------------------------------------
+ 1 file changed, 1 insertion(+), 86 deletions(-)
+
+--- a/drivers/serial/serial_core.c
++++ b/drivers/serial/serial_core.c
+@@ -1526,91 +1526,6 @@ static void uart_dtr_rts(struct tty_port
+ uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
+ }
+
+-/*
+- * Block the open until the port is ready. We must be called with
+- * the per-port semaphore held.
+- */
+-static int
+-uart_block_til_ready(struct file *filp, struct uart_state *state)
+-{
+- DECLARE_WAITQUEUE(wait, current);
+- struct tty_port *port = &state->port;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&port->lock, flags);
+- if (!tty_hung_up_p(filp))
+- port->count--;
+- port->blocked_open++;
+- spin_unlock_irqrestore(&port->lock, flags);
+-
+- add_wait_queue(&port->open_wait, &wait);
+- while (1) {
+- set_current_state(TASK_INTERRUPTIBLE);
+-
+- /*
+- * If we have been hung up, tell userspace/restart open.
+- */
+- if (tty_hung_up_p(filp) || port->tty == NULL)
+- break;
+-
+- /*
+- * If the port has been closed, tell userspace/restart open.
+- */
+- if (!(port->flags & ASYNC_INITIALIZED))
+- break;
+-
+- /*
+- * If non-blocking mode is set, or CLOCAL mode is set,
+- * we don't want to wait for the modem status lines to
+- * indicate that the port is ready.
+- *
+- * Also, if the port is not enabled/configured, we want
+- * to allow the open to succeed here. Note that we will
+- * have set TTY_IO_ERROR for a non-existant port.
+- */
+- if ((filp->f_flags & O_NONBLOCK) ||
+- (port->tty->termios->c_cflag & CLOCAL) ||
+- (port->tty->flags & (1 << TTY_IO_ERROR)))
+- break;
+-
+- /*
+- * Set DTR to allow modem to know we're waiting. Do
+- * not set RTS here - we want to make sure we catch
+- * the data from the modem.
+- */
+- if (port->tty->termios->c_cflag & CBAUD)
+- tty_port_raise_dtr_rts(port);
+-
+- /*
+- * and wait for the carrier to indicate that the
+- * modem is ready for us.
+- */
+- if (tty_port_carrier_raised(port))
+- break;
+-
+- schedule();
+-
+- if (signal_pending(current))
+- break;
+- }
+- set_current_state(TASK_RUNNING);
+- remove_wait_queue(&port->open_wait, &wait);
+-
+- spin_lock_irqsave(&port->lock, flags);
+- if (!tty_hung_up_p(filp))
+- port->count++;
+- port->blocked_open--;
+- spin_unlock_irqrestore(&port->lock, flags);
+-
+- if (signal_pending(current))
+- return -ERESTARTSYS;
+-
+- if (!port->tty || tty_hung_up_p(filp))
+- return -EAGAIN;
+-
+- return 0;
+-}
+-
+ static struct uart_state *uart_get(struct uart_driver *drv, int line)
+ {
+ struct uart_state *state;
+@@ -1719,7 +1634,7 @@ static int uart_open(struct tty_struct *
+ */
+ mutex_unlock(&port->mutex);
+ if (retval == 0)
+- retval = uart_block_til_ready(filp, state);
++ retval = tty_port_block_til_ready(port, tty, filp);
+
+ /*
+ * If this is the first open to succeed, adjust things to suit.
diff --git a/tty/tty-fix-console_sem-lock-order.patch b/tty/tty-fix-console_sem-lock-order.patch
new file mode 100644
index 00000000000000..2a79928346d3d4
--- /dev/null
+++ b/tty/tty-fix-console_sem-lock-order.patch
@@ -0,0 +1,42 @@
+From arnd@arndb.de Wed Jun 16 13:42:16 2010
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Tue, 1 Jun 2010 22:53:03 +0200
+Subject: tty: fix console_sem lock order
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>
+Message-ID: <1275425591-8803-24-git-send-email-arnd@arndb.de>
+
+
+vgacon_do_font_op releases and reacquires the BTM while holding
+console_sem. This violates the rule that BTM has to be the
+outer lock whenever we hold both.
+
+There does not seem to be any reason to give up the BTM here,
+so just stop doing that.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/video/console/vgacon.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/video/console/vgacon.c
++++ b/drivers/video/console/vgacon.c
+@@ -1108,7 +1108,6 @@ static int vgacon_do_font_op(struct vgas
+ charmap += 4 * cmapsz;
+ #endif
+
+- tty_unlock();
+ spin_lock_irq(&vga_lock);
+ /* First, the Sequencer */
+ vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
+@@ -1192,7 +1191,6 @@ static int vgacon_do_font_op(struct vgas
+ vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);
+ }
+ spin_unlock_irq(&vga_lock);
+- tty_lock();
+ return 0;
+ }
+
diff --git a/tty/tty-implement-btm-as-mutex-instead-of-bkl.patch b/tty/tty-implement-btm-as-mutex-instead-of-bkl.patch
new file mode 100644
index 00000000000000..ce84ae064e6b9a
--- /dev/null
+++ b/tty/tty-implement-btm-as-mutex-instead-of-bkl.patch
@@ -0,0 +1,139 @@
+From arnd@arndb.de Wed Jun 16 13:46:10 2010
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Tue, 1 Jun 2010 22:53:09 +0200
+Subject: tty: implement BTM as mutex instead of BKL
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>
+Message-ID: <1275425591-8803-30-git-send-email-arnd@arndb.de>
+
+
+The tty locking now follows the rules for mutexes, so
+we can replace the BKL usage with a new subsystem
+wide mutex.
+
+This patch for now makes the new behaviour an optional
+experimental feature that can be enabled for testing
+purposes.
+
+Using a regular mutex here will change the behaviour
+when blocked on the BTM from spinning to sleeping,
+but that should not be visible to the user.
+
+Using the mutex also means that all the BTM is now
+covered by lockdep.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/Makefile | 1 +
+ drivers/char/tty_mutex.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/tty.h | 8 ++++++++
+ lib/Kconfig.debug | 10 ++++++++++
+ 4 files changed, 66 insertions(+)
+
+--- a/drivers/char/Makefile
++++ b/drivers/char/Makefile
+@@ -9,6 +9,7 @@ FONTMAPFILE = cp437.uni
+
+ obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o
+
++obj-$(CONFIG_TTY_MUTEX) += tty_mutex.o
+ obj-$(CONFIG_LEGACY_PTYS) += pty.o
+ obj-$(CONFIG_UNIX98_PTYS) += pty.o
+ obj-y += misc.o
+--- /dev/null
++++ b/drivers/char/tty_mutex.c
+@@ -0,0 +1,47 @@
++/*
++ * drivers/char/tty_lock.c
++ */
++#include <linux/tty.h>
++#include <linux/module.h>
++#include <linux/kallsyms.h>
++#include <linux/semaphore.h>
++#include <linux/sched.h>
++
++/*
++ * The 'big tty mutex'
++ *
++ * This mutex is taken and released by tty_lock() and tty_unlock(),
++ * replacing the older big kernel lock.
++ * It can no longer be taken recursively, and does not get
++ * released implicitly while sleeping.
++ *
++ * Don't use in new code.
++ */
++static DEFINE_MUTEX(big_tty_mutex);
++struct task_struct *__big_tty_mutex_owner;
++EXPORT_SYMBOL_GPL(__big_tty_mutex_owner);
++
++/*
++ * Getting the big tty mutex.
++ */
++void __lockfunc tty_lock(void)
++{
++ struct task_struct *task = current;
++
++ WARN_ON(__big_tty_mutex_owner == task);
++
++ mutex_lock(&big_tty_mutex);
++ __big_tty_mutex_owner = task;
++}
++EXPORT_SYMBOL(tty_lock);
++
++void __lockfunc tty_unlock(void)
++{
++ struct task_struct *task = current;
++
++ WARN_ON(__big_tty_mutex_owner != task);
++ __big_tty_mutex_owner = NULL;
++
++ mutex_unlock(&big_tty_mutex);
++}
++EXPORT_SYMBOL(tty_unlock);
+--- a/include/linux/tty.h
++++ b/include/linux/tty.h
+@@ -574,7 +574,14 @@ extern int vt_ioctl(struct tty_struct *t
+ extern long vt_compat_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg);
+
++/* tty_mutex.c */
+ /* functions for preparation of BKL removal */
++#ifdef CONFIG_TTY_MUTEX
++extern void __lockfunc tty_lock(void) __acquires(tty_lock);
++extern void __lockfunc tty_unlock(void) __releases(tty_lock);
++extern struct task_struct *__big_tty_mutex_owner;
++#define tty_locked() (current == __big_tty_mutex_owner)
++#else
+ static inline void tty_lock(void) __acquires(kernel_lock)
+ {
+ #ifdef CONFIG_LOCK_KERNEL
+@@ -588,6 +595,7 @@ static inline void tty_unlock(void) __re
+ unlock_kernel();
+ }
+ #define tty_locked() (kernel_locked())
++#endif
+
+ /*
+ * wait_event_interruptible_tty -- wait for a condition with the tty lock held
+--- a/lib/Kconfig.debug
++++ b/lib/Kconfig.debug
+@@ -428,6 +428,16 @@ config RT_MUTEX_TESTER
+ help
+ This option enables a rt-mutex tester.
+
++config TTY_MUTEX
++ bool "Use a mutex instead of BKL for TTY locking"
++ depends on EXPERIMENTAL && SMP
++ help
++ The TTY subsystem traditionally depends on the big kernel lock
++ for serialization. Saying Y here replaces the BKL with the Big
++ TTY Mutex (BTM).
++ Building a kernel without the BKL is only possible with TTY_MUTEX
++ enabled.
++
+ config DEBUG_SPINLOCK
+ bool "Spinlock and rw-lock debugging: basic checks"
+ depends on DEBUG_KERNEL
diff --git a/tty/tty-introduce-wait_event_interruptible_tty.patch b/tty/tty-introduce-wait_event_interruptible_tty.patch
new file mode 100644
index 00000000000000..47f854759382de
--- /dev/null
+++ b/tty/tty-introduce-wait_event_interruptible_tty.patch
@@ -0,0 +1,191 @@
+From arnd@arndb.de Wed Jun 16 13:43:07 2010
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Tue, 1 Jun 2010 22:53:05 +0200
+Subject: tty: introduce wait_event_interruptible_tty
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>
+Message-ID: <1275425591-8803-26-git-send-email-arnd@arndb.de>
+
+
+Calling wait_event_interruptible implicitly
+releases the BKL when it sleeps, but we need
+to do this explcitly when we have converted
+it to a mutex.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/cyclades.c | 2 +-
+ drivers/char/istallion.c | 12 ++++++++----
+ drivers/char/n_r3964.c | 2 +-
+ drivers/char/tty_port.c | 2 +-
+ drivers/char/vt_ioctl.c | 2 +-
+ drivers/serial/crisv10.c | 4 ++--
+ include/linux/tty.h | 42 ++++++++++++++++++++++++++++++++++++++++++
+ 7 files changed, 56 insertions(+), 10 deletions(-)
+
+--- a/drivers/char/cyclades.c
++++ b/drivers/char/cyclades.c
+@@ -1607,7 +1607,7 @@ static int cy_open(struct tty_struct *tt
+ * If the port is the middle of closing, bail out now
+ */
+ if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
+- wait_event_interruptible(info->port.close_wait,
++ wait_event_interruptible_tty(info->port.close_wait,
+ !(info->port.flags & ASYNC_CLOSING));
+ return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
+ }
+--- a/drivers/char/istallion.c
++++ b/drivers/char/istallion.c
+@@ -954,7 +954,7 @@ static int stli_rawopen(struct stlibrd *
+ * order of opens and closes may not be preserved across shared
+ * memory, so we must wait until it is complete.
+ */
+- wait_event_interruptible(portp->raw_wait,
++ wait_event_interruptible_tty(portp->raw_wait,
+ !test_bit(ST_CLOSING, &portp->state));
+ if (signal_pending(current)) {
+ return -ERESTARTSYS;
+@@ -989,7 +989,7 @@ static int stli_rawopen(struct stlibrd *
+ set_bit(ST_OPENING, &portp->state);
+ spin_unlock_irqrestore(&brd_lock, flags);
+
+- wait_event_interruptible(portp->raw_wait,
++ wait_event_interruptible_tty(portp->raw_wait,
+ !test_bit(ST_OPENING, &portp->state));
+ if (signal_pending(current))
+ rc = -ERESTARTSYS;
+@@ -1020,7 +1020,7 @@ static int stli_rawclose(struct stlibrd
+ * occurs on this port.
+ */
+ if (wait) {
+- wait_event_interruptible(portp->raw_wait,
++ wait_event_interruptible_tty(portp->raw_wait,
+ !test_bit(ST_CLOSING, &portp->state));
+ if (signal_pending(current)) {
+ return -ERESTARTSYS;
+@@ -1052,7 +1052,7 @@ static int stli_rawclose(struct stlibrd
+ * to come back.
+ */
+ rc = 0;
+- wait_event_interruptible(portp->raw_wait,
++ wait_event_interruptible_tty(portp->raw_wait,
+ !test_bit(ST_CLOSING, &portp->state));
+ if (signal_pending(current))
+ rc = -ERESTARTSYS;
+@@ -1073,6 +1073,10 @@ static int stli_rawclose(struct stlibrd
+
+ static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback)
+ {
++ /*
++ * no need for wait_event_tty because clearing ST_CMDING cannot block
++ * on BTM
++ */
+ wait_event_interruptible(portp->raw_wait,
+ !test_bit(ST_CMDING, &portp->state));
+ if (signal_pending(current))
+--- a/drivers/char/n_r3964.c
++++ b/drivers/char/n_r3964.c
+@@ -1079,7 +1079,7 @@ static ssize_t r3964_read(struct tty_str
+ goto unlock;
+ }
+ /* block until there is a message: */
+- wait_event_interruptible(pInfo->read_wait,
++ wait_event_interruptible_tty(pInfo->read_wait,
+ (pMsg = remove_msg(pInfo, pClient)));
+ }
+
+--- a/drivers/char/tty_port.c
++++ b/drivers/char/tty_port.c
+@@ -231,7 +231,7 @@ int tty_port_block_til_ready(struct tty_
+
+ /* block if port is in the process of being closed */
+ if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+- wait_event_interruptible(port->close_wait,
++ wait_event_interruptible_tty(port->close_wait,
+ !(port->flags & ASYNC_CLOSING));
+ if (port->flags & ASYNC_HUP_NOTIFY)
+ return -EAGAIN;
+--- a/drivers/char/vt_ioctl.c
++++ b/drivers/char/vt_ioctl.c
+@@ -133,7 +133,7 @@ static void vt_event_wait(struct vt_even
+ list_add(&vw->list, &vt_events);
+ spin_unlock_irqrestore(&vt_event_lock, flags);
+ /* Wait for it to pass */
+- wait_event_interruptible(vt_event_waitqueue, vw->done);
++ wait_event_interruptible_tty(vt_event_waitqueue, vw->done);
+ /* Dequeue it */
+ spin_lock_irqsave(&vt_event_lock, flags);
+ list_del(&vw->list);
+--- a/drivers/serial/crisv10.c
++++ b/drivers/serial/crisv10.c
+@@ -3981,7 +3981,7 @@ block_til_ready(struct tty_struct *tty,
+ */
+ if (tty_hung_up_p(filp) ||
+ (info->flags & ASYNC_CLOSING)) {
+- wait_event_interruptible(info->close_wait,
++ wait_event_interruptible_tty(info->close_wait,
+ !(info->flags & ASYNC_CLOSING));
+ #ifdef SERIAL_DO_RESTART
+ if (info->flags & ASYNC_HUP_NOTIFY)
+@@ -4139,7 +4139,7 @@ rs_open(struct tty_struct *tty, struct f
+ */
+ if (tty_hung_up_p(filp) ||
+ (info->flags & ASYNC_CLOSING)) {
+- wait_event_interruptible(info->close_wait,
++ wait_event_interruptible_tty(info->close_wait,
+ !(info->flags & ASYNC_CLOSING));
+ #ifdef SERIAL_DO_RESTART
+ return ((info->flags & ASYNC_HUP_NOTIFY) ?
+--- a/include/linux/tty.h
++++ b/include/linux/tty.h
+@@ -603,5 +603,47 @@ static inline void tty_unlock(void) __re
+ }
+ #define tty_locked() (kernel_locked())
+
++/*
++ * wait_event_interruptible_tty -- wait for a condition with the tty lock held
++ *
++ * The condition we are waiting for might take a long time to
++ * become true, or might depend on another thread taking the
++ * BTM. In either case, we need to drop the BTM to guarantee
++ * forward progress. This is a leftover from the conversion
++ * from the BKL and should eventually get removed as the BTM
++ * falls out of use.
++ *
++ * Do not use in new code.
++ */
++#define wait_event_interruptible_tty(wq, condition) \
++({ \
++ int __ret = 0; \
++ if (!(condition)) { \
++ __wait_event_interruptible_tty(wq, condition, __ret); \
++ } \
++ __ret; \
++})
++
++#define __wait_event_interruptible_tty(wq, condition, ret) \
++do { \
++ DEFINE_WAIT(__wait); \
++ \
++ for (;;) { \
++ prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE); \
++ if (condition) \
++ break; \
++ if (!signal_pending(current)) { \
++ tty_unlock(); \
++ schedule(); \
++ tty_lock(); \
++ continue; \
++ } \
++ ret = -ERESTARTSYS; \
++ break; \
++ } \
++ finish_wait(&wq, &__wait); \
++} while (0)
++
++
+ #endif /* __KERNEL__ */
+ #endif
diff --git a/tty/tty-make-vt-s-have-a-tty_port.patch b/tty/tty-make-vt-s-have-a-tty_port.patch
new file mode 100644
index 00000000000000..2ae2becfbe6431
--- /dev/null
+++ b/tty/tty-make-vt-s-have-a-tty_port.patch
@@ -0,0 +1,53 @@
+From arnd@arndb.de Wed Jun 16 13:31:12 2010
+From: Alan Cox <alan@linux.intel.com>
+Date: Tue, 1 Jun 2010 22:52:55 +0200
+Subject: tty: Make vt's have a tty_port
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>, Alan Cox <alan@linux.intel.com>
+Message-ID: <1275425591-8803-16-git-send-email-arnd@arndb.de>
+
+
+From: Alan Cox <alan@linux.intel.com>
+
+The vt layer isn't safely handling reference counts to tty object on the input
+side. Add a tty port structure to the vt layer in order to implement this using
+the standard helpers.
+
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/vt.c | 2 ++
+ include/linux/console_struct.h | 2 ++
+ 2 files changed, 4 insertions(+)
+
+--- a/drivers/char/vt.c
++++ b/drivers/char/vt.c
+@@ -773,6 +773,7 @@ int vc_allocate(unsigned int currcons) /
+ if (!vc)
+ return -ENOMEM;
+ vc_cons[currcons].d = vc;
++ tty_port_init(&vc->port);
+ INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
+ visual_init(vc, currcons, 1);
+ if (!*vc->vc_uni_pagedir_loc)
+@@ -2910,6 +2911,7 @@ static int __init con_init(void)
+ for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
+ vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
+ INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
++ tty_port_init(&vc->port);
+ visual_init(vc, currcons, 1);
+ vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
+ vc_init(vc, vc->vc_rows, vc->vc_cols,
+--- a/include/linux/console_struct.h
++++ b/include/linux/console_struct.h
+@@ -21,6 +21,8 @@ struct vt_struct;
+ #define NPAR 16
+
+ struct vc_data {
++ struct tty_port port; /* Upper level data */
++
+ unsigned short vc_num; /* Console number */
+ unsigned int vc_cols; /* [#] Console size */
+ unsigned int vc_rows;
diff --git a/tty/tty-move-the-vt_tty-field-from-the-vc_data-into-the-standard-tty_port.patch b/tty/tty-move-the-vt_tty-field-from-the-vc_data-into-the-standard-tty_port.patch
new file mode 100644
index 00000000000000..47781353c35c88
--- /dev/null
+++ b/tty/tty-move-the-vt_tty-field-from-the-vc_data-into-the-standard-tty_port.patch
@@ -0,0 +1,134 @@
+From arnd@arndb.de Wed Jun 16 13:33:03 2010
+From: Alan Cox <alan@linux.intel.com>
+Date: Tue, 1 Jun 2010 22:52:56 +0200
+Subject: tty: Move the vt_tty field from the vc_data into the standard tty_port
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>, Alan Cox <alan@linux.intel.com>
+Message-ID: <1275425591-8803-17-git-send-email-arnd@arndb.de>
+
+
+From: Alan Cox <alan@linux.intel.com>
+
+This takes all the tty references through the expected interface points so
+we can refcount them.
+
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/keyboard.c | 10 +++++-----
+ drivers/char/vt.c | 10 +++++-----
+ drivers/char/vt_ioctl.c | 2 +-
+ include/linux/console_struct.h | 1 -
+ 4 files changed, 11 insertions(+), 12 deletions(-)
+
+--- a/drivers/char/keyboard.c
++++ b/drivers/char/keyboard.c
+@@ -299,7 +299,7 @@ int kbd_rate(struct kbd_repeat *rep)
+ */
+ static void put_queue(struct vc_data *vc, int ch)
+ {
+- struct tty_struct *tty = vc->vc_tty;
++ struct tty_struct *tty = vc->port.tty;
+
+ if (tty) {
+ tty_insert_flip_char(tty, ch, 0);
+@@ -309,7 +309,7 @@ static void put_queue(struct vc_data *vc
+
+ static void puts_queue(struct vc_data *vc, char *cp)
+ {
+- struct tty_struct *tty = vc->vc_tty;
++ struct tty_struct *tty = vc->port.tty;
+
+ if (!tty)
+ return;
+@@ -485,7 +485,7 @@ static void fn_show_ptregs(struct vc_dat
+
+ static void fn_hold(struct vc_data *vc)
+ {
+- struct tty_struct *tty = vc->vc_tty;
++ struct tty_struct *tty = vc->port.tty;
+
+ if (rep || !tty)
+ return;
+@@ -563,7 +563,7 @@ static void fn_inc_console(struct vc_dat
+
+ static void fn_send_intr(struct vc_data *vc)
+ {
+- struct tty_struct *tty = vc->vc_tty;
++ struct tty_struct *tty = vc->port.tty;
+
+ if (!tty)
+ return;
+@@ -1162,7 +1162,7 @@ static void kbd_keycode(unsigned int key
+ struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
+ int rc;
+
+- tty = vc->vc_tty;
++ tty = vc->port.tty;
+
+ if (tty && (!tty->driver_data)) {
+ /* No driver data? Strange. Okay we fix it then. */
+--- a/drivers/char/vt.c
++++ b/drivers/char/vt.c
+@@ -962,12 +962,12 @@ static int vc_do_resize(struct tty_struc
+ * Resize a virtual console as seen from the console end of things. We
+ * use the common vc_do_resize methods to update the structures. The
+ * caller must hold the console sem to protect console internals and
+- * vc->vc_tty
++ * vc->port.tty
+ */
+
+ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
+ {
+- return vc_do_resize(vc->vc_tty, vc, cols, rows);
++ return vc_do_resize(vc->port.tty, vc, cols, rows);
+ }
+
+ /**
+@@ -2796,12 +2796,12 @@ static int con_open(struct tty_struct *t
+ struct vc_data *vc = vc_cons[currcons].d;
+
+ /* Still being freed */
+- if (vc->vc_tty) {
++ if (vc->port.tty) {
+ release_console_sem();
+ return -ERESTARTSYS;
+ }
+ tty->driver_data = vc;
+- vc->vc_tty = tty;
++ vc->port.tty = tty;
+
+ if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
+ tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
+@@ -2829,7 +2829,7 @@ static void con_shutdown(struct tty_stru
+ struct vc_data *vc = tty->driver_data;
+ BUG_ON(vc == NULL);
+ acquire_console_sem();
+- vc->vc_tty = NULL;
++ vc->port.tty = NULL;
+ release_console_sem();
+ tty_shutdown(tty);
+ }
+--- a/drivers/char/vt_ioctl.c
++++ b/drivers/char/vt_ioctl.c
+@@ -1369,7 +1369,7 @@ void vc_SAK(struct work_struct *work)
+ acquire_console_sem();
+ vc = vc_con->d;
+ if (vc) {
+- tty = vc->vc_tty;
++ tty = vc->port.tty;
+ /*
+ * SAK should also work in all raw modes and reset
+ * them properly.
+--- a/include/linux/console_struct.h
++++ b/include/linux/console_struct.h
+@@ -58,7 +58,6 @@ struct vc_data {
+ /* VT terminal data */
+ unsigned int vc_state; /* Escape sequence parser state */
+ unsigned int vc_npar,vc_par[NPAR]; /* Parameters of current escape sequence */
+- struct tty_struct *vc_tty; /* TTY we are attached to */
+ /* data for manual vt switching */
+ struct vt_mode vt_mode;
+ struct pid *vt_pid;
diff --git a/tty/tty-never-hold-btm-while-getting-tty_mutex.patch b/tty/tty-never-hold-btm-while-getting-tty_mutex.patch
new file mode 100644
index 00000000000000..568d2747ee81ca
--- /dev/null
+++ b/tty/tty-never-hold-btm-while-getting-tty_mutex.patch
@@ -0,0 +1,111 @@
+From arnd@arndb.de Wed Jun 16 13:41:48 2010
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Tue, 1 Jun 2010 22:53:02 +0200
+Subject: tty: never hold BTM while getting tty_mutex
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>
+Message-ID: <1275425591-8803-23-git-send-email-arnd@arndb.de>
+
+
+tty_mutex is never taken with the BTM held, except for
+two corner cases that are worked around here.
+We give up the BTM before calling tty_release() in the
+error path of tty_open().
+Similarly, we reorder the locking in ptmx_open()
+to get tty_mutex before the BTM.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/pty.c | 24 +++++++++++-------------
+ drivers/char/tty_io.c | 12 ++++++------
+ 2 files changed, 17 insertions(+), 19 deletions(-)
+
+--- a/drivers/char/pty.c
++++ b/drivers/char/pty.c
+@@ -626,7 +626,7 @@ static const struct tty_operations pty_u
+ * allocated_ptys_lock handles the list of free pty numbers
+ */
+
+-static int __ptmx_open(struct inode *inode, struct file *filp)
++static int ptmx_open(struct inode *inode, struct file *filp)
+ {
+ struct tty_struct *tty;
+ int retval;
+@@ -635,11 +635,14 @@ static int __ptmx_open(struct inode *ino
+ nonseekable_open(inode, filp);
+
+ /* find a device that is not in use. */
++ tty_lock();
+ index = devpts_new_index(inode);
++ tty_unlock();
+ if (index < 0)
+ return index;
+
+ mutex_lock(&tty_mutex);
++ tty_lock();
+ tty = tty_init_dev(ptm_driver, index, 1);
+ mutex_unlock(&tty_mutex);
+
+@@ -657,24 +660,19 @@ static int __ptmx_open(struct inode *ino
+ goto out1;
+
+ retval = ptm_driver->ops->open(tty, filp);
+- if (!retval)
+- return 0;
++ if (retval)
++ goto out2;
+ out1:
++ tty_unlock();
++ return retval;
++out2:
++ tty_unlock();
+ tty_release(inode, filp);
+ return retval;
+ out:
+ devpts_kill_index(inode, index);
+- return retval;
+-}
+-
+-static int ptmx_open(struct inode *inode, struct file *filp)
+-{
+- int ret;
+-
+- tty_lock();
+- ret = __ptmx_open(inode, filp);
+ tty_unlock();
+- return ret;
++ return retval;
+ }
+
+ static struct file_operations ptmx_fops;
+--- a/drivers/char/tty_io.c
++++ b/drivers/char/tty_io.c
+@@ -1866,19 +1866,19 @@ got_driver:
+ printk(KERN_DEBUG "error %d in opening %s...", retval,
+ tty->name);
+ #endif
++ tty_unlock(); /* need to call tty_release without BTM */
+ tty_release(inode, filp);
+- if (retval != -ERESTARTSYS) {
+- tty_unlock();
++ if (retval != -ERESTARTSYS)
+ return retval;
+- }
+- if (signal_pending(current)) {
+- tty_unlock();
++
++ if (signal_pending(current))
+ return retval;
+- }
++
+ schedule();
+ /*
+ * Need to reset f_op in case a hangup happened.
+ */
++ tty_lock();
+ if (filp->f_op == &hung_up_tty_fops)
+ filp->f_op = &tty_fops;
+ tty_unlock();
diff --git a/tty/tty-release-btm-while-sleeping-in-block_til_ready.patch b/tty/tty-release-btm-while-sleeping-in-block_til_ready.patch
new file mode 100644
index 00000000000000..6d7656ab1da5ad
--- /dev/null
+++ b/tty/tty-release-btm-while-sleeping-in-block_til_ready.patch
@@ -0,0 +1,175 @@
+From arnd@arndb.de Wed Jun 16 13:47:56 2010
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Tue, 1 Jun 2010 22:53:10 +0200
+Subject: tty: release BTM while sleeping in block_til_ready
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>
+Message-ID: <1275425591-8803-31-git-send-email-arnd@arndb.de>
+
+
+Most tty drivers may block while opening a device.
+Since this possibly depends on another thread
+closing it first and both threads may need the BTM,
+we need to release it here.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/amiserial.c | 2 ++
+ drivers/char/ip2/ip2main.c | 4 ++++
+ drivers/char/serial167.c | 4 +++-
+ drivers/char/specialix.c | 2 ++
+ drivers/char/synclink.c | 2 ++
+ drivers/char/synclink_gt.c | 2 ++
+ drivers/char/synclinkmp.c | 2 ++
+ drivers/char/tty_port.c | 2 ++
+ drivers/serial/68328serial.c | 2 ++
+ drivers/serial/68360serial.c | 2 ++
+ drivers/serial/crisv10.c | 2 ++
+ 11 files changed, 25 insertions(+), 1 deletion(-)
+
+--- a/drivers/char/amiserial.c
++++ b/drivers/char/amiserial.c
+@@ -1710,7 +1710,9 @@ static int block_til_ready(struct tty_st
+ printk("block_til_ready blocking: ttys%d, count = %d\n",
+ info->line, state->count);
+ #endif
++ tty_unlock();
+ schedule();
++ tty_lock();
+ }
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&info->open_wait, &wait);
+--- a/drivers/char/ip2/ip2main.c
++++ b/drivers/char/ip2/ip2main.c
+@@ -1486,7 +1486,9 @@ ip2_open( PTTY tty, struct file *pFile )
+
+ if ( tty_hung_up_p(pFile) || ( pCh->flags & ASYNC_CLOSING )) {
+ if ( pCh->flags & ASYNC_CLOSING ) {
++ tty_unlock();
+ schedule();
++ tty_lock();
+ }
+ if ( tty_hung_up_p(pFile) ) {
+ set_current_state( TASK_RUNNING );
+@@ -1548,7 +1550,9 @@ ip2_open( PTTY tty, struct file *pFile )
+ rc = (( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS);
+ break;
+ }
++ tty_unlock();
+ schedule();
++ tty_lock();
+ }
+ set_current_state( TASK_RUNNING );
+ remove_wait_queue(&pCh->open_wait, &wait);
+--- a/drivers/char/serial167.c
++++ b/drivers/char/serial167.c
+@@ -1786,7 +1786,9 @@ block_til_ready(struct tty_struct *tty,
+ tty->name, info->count);
+ /**/
+ #endif
+- schedule();
++ tty_unlock();
++ schedule();
++ tty_lock();
+ }
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&info->open_wait, &wait);
+--- a/drivers/char/specialix.c
++++ b/drivers/char/specialix.c
+@@ -1365,7 +1365,9 @@ static int block_til_ready(struct tty_st
+ retval = -ERESTARTSYS;
+ break;
+ }
++ tty_unlock();
+ schedule();
++ tty_lock();
+ }
+
+ set_current_state(TASK_RUNNING);
+--- a/drivers/char/synclink.c
++++ b/drivers/char/synclink.c
+@@ -3349,7 +3349,9 @@ static int block_til_ready(struct tty_st
+ printk("%s(%d):block_til_ready blocking on %s count=%d\n",
+ __FILE__,__LINE__, tty->driver->name, port->count );
+
++ tty_unlock();
+ schedule();
++ tty_lock();
+ }
+
+ set_current_state(TASK_RUNNING);
+--- a/drivers/char/synclink_gt.c
++++ b/drivers/char/synclink_gt.c
+@@ -3244,7 +3244,9 @@ static int block_til_ready(struct tty_st
+ }
+
+ DBGINFO(("%s block_til_ready wait\n", tty->driver->name));
++ tty_unlock();
+ schedule();
++ tty_lock();
+ }
+
+ set_current_state(TASK_RUNNING);
+--- a/drivers/char/synclinkmp.c
++++ b/drivers/char/synclinkmp.c
+@@ -3365,7 +3365,9 @@ static int block_til_ready(struct tty_st
+ printk("%s(%d):%s block_til_ready() count=%d\n",
+ __FILE__,__LINE__, tty->driver->name, port->count );
+
++ tty_unlock();
+ schedule();
++ tty_lock();
+ }
+
+ set_current_state(TASK_RUNNING);
+--- a/drivers/char/tty_port.c
++++ b/drivers/char/tty_port.c
+@@ -294,7 +294,9 @@ int tty_port_block_til_ready(struct tty_
+ retval = -ERESTARTSYS;
+ break;
+ }
++ tty_unlock();
+ schedule();
++ tty_lock();
+ }
+ finish_wait(&port->open_wait, &wait);
+
+--- a/drivers/serial/68328serial.c
++++ b/drivers/serial/68328serial.c
+@@ -1235,7 +1235,9 @@ static int block_til_ready(struct tty_st
+ retval = -ERESTARTSYS;
+ break;
+ }
++ tty_unlock();
+ schedule();
++ tty_lock();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
+--- a/drivers/serial/68360serial.c
++++ b/drivers/serial/68360serial.c
+@@ -1860,7 +1860,9 @@ static int block_til_ready(struct tty_st
+ printk("block_til_ready blocking: ttys%d, count = %d\n",
+ info->line, state->count);
+ #endif
++ tty_unlock();
+ schedule();
++ tty_lock();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
+--- a/drivers/serial/crisv10.c
++++ b/drivers/serial/crisv10.c
+@@ -4055,7 +4055,9 @@ block_til_ready(struct tty_struct *tty,
+ printk("block_til_ready blocking: ttyS%d, count = %d\n",
+ info->line, info->count);
+ #endif
++ tty_unlock();
+ schedule();
++ tty_lock();
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&info->open_wait, &wait);
diff --git a/tty/tty-remove-tty_lock_nested.patch b/tty/tty-remove-tty_lock_nested.patch
new file mode 100644
index 00000000000000..544676d2f12f76
--- /dev/null
+++ b/tty/tty-remove-tty_lock_nested.patch
@@ -0,0 +1,219 @@
+From arnd@arndb.de Wed Jun 16 13:45:36 2010
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Tue, 1 Jun 2010 22:53:08 +0200
+Subject: tty: remove tty_lock_nested
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>
+Message-ID: <1275425591-8803-29-git-send-email-arnd@arndb.de>
+
+
+This changes all remaining users of tty_lock_nested
+to be non-recursive, which lets us kill this function.
+As a consequence, we won't need to keep the lock count
+any more, which allows more simplifications later.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/pty.c | 2 +-
+ drivers/char/selection.c | 4 ++--
+ drivers/char/tty_io.c | 41 ++++++++++++++++++++---------------------
+ drivers/char/tty_ldisc.c | 3 +--
+ include/linux/tty.h | 16 +---------------
+ 5 files changed, 25 insertions(+), 41 deletions(-)
+
+--- a/drivers/char/pty.c
++++ b/drivers/char/pty.c
+@@ -62,7 +62,7 @@ static void pty_close(struct tty_struct
+ if (tty->driver == ptm_driver)
+ devpts_pty_kill(tty->link);
+ #endif
+- tty_vhangup(tty->link);
++ tty_vhangup_locked(tty->link);
+ }
+ }
+
+--- a/drivers/char/selection.c
++++ b/drivers/char/selection.c
+@@ -313,7 +313,8 @@ int paste_selection(struct tty_struct *t
+ struct tty_ldisc *ld;
+ DECLARE_WAITQUEUE(wait, current);
+
+- tty_lock_nested(); /* always called with BTM from vt_ioctl */
++ /* always called with BTM from vt_ioctl */
++ WARN_ON(!tty_locked());
+
+ acquire_console_sem();
+ poke_blanked_console();
+@@ -343,6 +344,5 @@ int paste_selection(struct tty_struct *t
+ __set_current_state(TASK_RUNNING);
+
+ tty_ldisc_deref(ld);
+- tty_unlock();
+ return 0;
+ }
+--- a/drivers/char/tty_io.c
++++ b/drivers/char/tty_io.c
+@@ -492,10 +492,8 @@ EXPORT_SYMBOL_GPL(tty_wakeup);
+ * tasklist_lock to walk task list for hangup event
+ * ->siglock to protect ->signal/->sighand
+ */
+-static void do_tty_hangup(struct work_struct *work)
++void tty_vhangup_locked(struct tty_struct *tty)
+ {
+- struct tty_struct *tty =
+- container_of(work, struct tty_struct, hangup_work);
+ struct file *cons_filp = NULL;
+ struct file *filp, *f = NULL;
+ struct task_struct *p;
+@@ -517,8 +515,6 @@ static void do_tty_hangup(struct work_st
+ /* inuse_filps is protected by the single tty lock,
+ this really needs to change if we want to flush the
+ workqueue with the lock held */
+- tty_lock_nested(); /* called with BTM held from pty_close and
+- others */
+ check_tty_count(tty, "do_tty_hangup");
+
+ file_list_lock();
+@@ -598,11 +594,20 @@ static void do_tty_hangup(struct work_st
+ */
+ set_bit(TTY_HUPPED, &tty->flags);
+ tty_ldisc_enable(tty);
+- tty_unlock();
+ if (f)
+ fput(f);
+ }
+
++static void do_tty_hangup(struct work_struct *work)
++{
++ struct tty_struct *tty =
++ container_of(work, struct tty_struct, hangup_work);
++
++ tty_lock();
++ tty_vhangup_locked(tty);
++ tty_unlock();
++}
++
+ /**
+ * tty_hangup - trigger a hangup event
+ * @tty: tty to hangup
+@@ -638,7 +643,9 @@ void tty_vhangup(struct tty_struct *tty)
+
+ printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
+ #endif
+- do_tty_hangup(&tty->hangup_work);
++ tty_lock();
++ tty_vhangup_locked(tty);
++ tty_unlock();
+ }
+
+ EXPORT_SYMBOL(tty_vhangup);
+@@ -719,10 +726,12 @@ void disassociate_ctty(int on_exit)
+ tty = get_current_tty();
+ if (tty) {
+ tty_pgrp = get_pid(tty->pgrp);
+- tty_lock_nested(); /* see above */
+- if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
+- tty_vhangup(tty);
+- tty_unlock();
++ if (on_exit) {
++ tty_lock();
++ if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
++ tty_vhangup_locked(tty);
++ tty_unlock();
++ }
+ tty_kref_put(tty);
+ } else if (on_exit) {
+ struct pid *old_pgrp;
+@@ -1213,18 +1222,14 @@ static int tty_driver_install_tty(struct
+ int ret;
+
+ if (driver->ops->install) {
+- tty_lock_nested(); /* already called with BTM held */
+ ret = driver->ops->install(driver, tty);
+- tty_unlock();
+ return ret;
+ }
+
+ if (tty_init_termios(tty) == 0) {
+- tty_lock_nested();
+ tty_driver_kref_get(driver);
+ tty->count++;
+ driver->ttys[idx] = tty;
+- tty_unlock();
+ return 0;
+ }
+ return -ENOMEM;
+@@ -1317,15 +1322,11 @@ struct tty_struct *tty_init_dev(struct t
+ struct tty_struct *tty;
+ int retval;
+
+- tty_lock_nested(); /* always called with tty lock held already */
+-
+ /* Check if pty master is being opened multiple times */
+ if (driver->subtype == PTY_TYPE_MASTER &&
+ (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
+- tty_unlock();
+ return ERR_PTR(-EIO);
+ }
+- tty_unlock();
+
+ /*
+ * First time open is complex, especially for PTY devices.
+@@ -1369,9 +1370,7 @@ release_mem_out:
+ if (printk_ratelimit())
+ printk(KERN_INFO "tty_init_dev: ldisc open failed, "
+ "clearing slot %d\n", idx);
+- tty_lock_nested();
+ release_tty(tty, idx);
+- tty_unlock();
+ return ERR_PTR(retval);
+ }
+
+--- a/drivers/char/tty_ldisc.c
++++ b/drivers/char/tty_ldisc.c
+@@ -450,9 +450,8 @@ static int tty_ldisc_open(struct tty_str
+ if (ld->ops->open) {
+ int ret;
+ /* BTM here locks versus a hangup event */
+- tty_lock_nested(); /* always held here already */
++ WARN_ON(!tty_locked());
+ ret = ld->ops->open(tty);
+- tty_unlock();
+ return ret;
+ }
+ return 0;
+--- a/include/linux/tty.h
++++ b/include/linux/tty.h
+@@ -416,6 +416,7 @@ extern int is_ignored(int sig);
+ extern int tty_signal(int sig, struct tty_struct *tty);
+ extern void tty_hangup(struct tty_struct *tty);
+ extern void tty_vhangup(struct tty_struct *tty);
++extern void tty_vhangup_locked(struct tty_struct *tty);
+ extern void tty_vhangup_self(void);
+ extern void tty_unhangup(struct file *filp);
+ extern int tty_hung_up_p(struct file *filp);
+@@ -574,21 +575,6 @@ extern long vt_compat_ioctl(struct tty_s
+ unsigned int cmd, unsigned long arg);
+
+ /* functions for preparation of BKL removal */
+-
+-/*
+- * tty_lock_nested get the tty_lock while potentially holding it
+- *
+- * The Big TTY Mutex is a recursive lock, meaning you can take it
+- * from a thread that is already holding it.
+- * This is bad for a number of reasons, so tty_lock_nested should
+- * really be used as rarely as possible. If a code location can
+- * be shown to never get called with this held already, it should
+- * use tty_lock() instead.
+- */
+-static inline void __lockfunc tty_lock_nested(void) __acquires(kernel_lock)
+-{
+- lock_kernel();
+-}
+ static inline void tty_lock(void) __acquires(kernel_lock)
+ {
+ #ifdef CONFIG_LOCK_KERNEL
diff --git a/tty/tty-reorder-ldisc-locking.patch b/tty/tty-reorder-ldisc-locking.patch
new file mode 100644
index 00000000000000..0ef070703e46b4
--- /dev/null
+++ b/tty/tty-reorder-ldisc-locking.patch
@@ -0,0 +1,117 @@
+From arnd@arndb.de Wed Jun 16 13:44:56 2010
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Tue, 1 Jun 2010 22:53:06 +0200
+Subject: tty: reorder ldisc locking
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>
+Message-ID: <1275425591-8803-27-git-send-email-arnd@arndb.de>
+
+
+We need to release the BTM in paste_selection() when
+sleeping in tty_ldisc_ref_wait to avoid deadlocks
+with tty_ldisc_enable.
+
+In tty_set_ldisc, we now always grab the BTM before
+taking the ldisc_mutex in order to avoid AB-BA
+deadlocks between the two.
+
+tty_ldisc_halt potentially blocks on a workqueue
+function that takes the BTM, so we must release
+the BTM before calling it.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/selection.c | 9 +++++++--
+ drivers/char/tty_ldisc.c | 24 ++++++++++++++++++++----
+ 2 files changed, 27 insertions(+), 6 deletions(-)
+
+--- a/drivers/char/selection.c
++++ b/drivers/char/selection.c
+@@ -319,8 +319,13 @@ int paste_selection(struct tty_struct *t
+ poke_blanked_console();
+ release_console_sem();
+
+- ld = tty_ldisc_ref_wait(tty);
+-
++ ld = tty_ldisc_ref(tty);
++ if (!ld) {
++ tty_unlock();
++ ld = tty_ldisc_ref_wait(tty);
++ tty_lock();
++ }
++
+ add_wait_queue(&vc->paste_wait, &wait);
+ while (sel_buffer && sel_buffer_lth > pasted) {
+ set_current_state(TASK_INTERRUPTIBLE);
+--- a/drivers/char/tty_ldisc.c
++++ b/drivers/char/tty_ldisc.c
+@@ -582,6 +582,7 @@ int tty_set_ldisc(struct tty_struct *tty
+
+ tty_wait_until_sent(tty, 0);
+
++ tty_lock();
+ mutex_lock(&tty->ldisc_mutex);
+
+ /*
+@@ -591,13 +592,13 @@ int tty_set_ldisc(struct tty_struct *tty
+
+ while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
+ mutex_unlock(&tty->ldisc_mutex);
++ tty_unlock();
+ wait_event(tty_ldisc_wait,
+ test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
++ tty_lock();
+ mutex_lock(&tty->ldisc_mutex);
+ }
+
+- tty_lock();
+-
+ set_bit(TTY_LDISC_CHANGING, &tty->flags);
+
+ /*
+@@ -634,8 +635,8 @@ int tty_set_ldisc(struct tty_struct *tty
+
+ flush_scheduled_work();
+
+- mutex_lock(&tty->ldisc_mutex);
+ tty_lock();
++ mutex_lock(&tty->ldisc_mutex);
+ if (test_bit(TTY_HUPPED, &tty->flags)) {
+ /* We were raced by the hangup method. It will have stomped
+ the ldisc data and closed the ldisc down */
+@@ -782,7 +783,20 @@ void tty_ldisc_hangup(struct tty_struct
+ * Avoid racing set_ldisc or tty_ldisc_release
+ */
+ mutex_lock(&tty->ldisc_mutex);
+- tty_ldisc_halt(tty);
++
++ /*
++ * this is like tty_ldisc_halt, but we need to give up
++ * the BTM before calling cancel_delayed_work_sync,
++ * which may need to wait for another function taking the BTM
++ */
++ clear_bit(TTY_LDISC, &tty->flags);
++ tty_unlock();
++ cancel_delayed_work_sync(&tty->buf.work);
++ mutex_unlock(&tty->ldisc_mutex);
++
++ tty_lock();
++ mutex_lock(&tty->ldisc_mutex);
++
+ /* At this point we have a closed ldisc and we want to
+ reopen it. We could defer this to the next open but
+ it means auditing a lot of other paths so this is
+@@ -853,8 +867,10 @@ void tty_ldisc_release(struct tty_struct
+ * race with the set_ldisc code path.
+ */
+
++ tty_unlock();
+ tty_ldisc_halt(tty);
+ flush_scheduled_work();
++ tty_lock();
+
+ mutex_lock(&tty->ldisc_mutex);
+ /*
diff --git a/tty/tty-replace-bkl-with-a-new-tty_lock.patch b/tty/tty-replace-bkl-with-a-new-tty_lock.patch
new file mode 100644
index 00000000000000..2f262e2222f876
--- /dev/null
+++ b/tty/tty-replace-bkl-with-a-new-tty_lock.patch
@@ -0,0 +1,1041 @@
+From arnd@arndb.de Wed Jun 16 13:40:23 2010
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Tue, 1 Jun 2010 22:53:01 +0200
+Subject: tty: replace BKL with a new tty_lock
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>
+Message-ID: <1275425591-8803-22-git-send-email-arnd@arndb.de>
+
+
+As a preparation for replacing the big kernel lock
+in the TTY layer, wrap all the callers in new
+macros tty_lock, tty_lock_nested and tty_unlock.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/amiserial.c | 16 ++---
+ drivers/char/briq_panel.c | 6 +-
+ drivers/char/n_hdlc.c | 16 ++---
+ drivers/char/n_r3964.c | 8 +-
+ drivers/char/pty.c | 4 -
+ drivers/char/selection.c | 4 -
+ drivers/char/serial167.c | 4 -
+ drivers/char/sx.c | 12 ++--
+ drivers/char/tty_io.c | 115 ++++++++++++++++++++++-------------------
+ drivers/char/tty_ldisc.c | 24 ++++----
+ drivers/char/vc_screen.c | 4 -
+ drivers/char/vt_ioctl.c | 10 +--
+ drivers/serial/68360serial.c | 4 -
+ drivers/serial/crisv10.c | 4 -
+ drivers/serial/serial_core.c | 10 +--
+ drivers/video/console/vgacon.c | 4 -
+ include/linux/tty.h | 31 +++++++++++
+ 17 files changed, 161 insertions(+), 115 deletions(-)
+
+--- a/drivers/char/amiserial.c
++++ b/drivers/char/amiserial.c
+@@ -1072,7 +1072,7 @@ static int get_serial_info(struct async_
+ if (!retinfo)
+ return -EFAULT;
+ memset(&tmp, 0, sizeof(tmp));
+- lock_kernel();
++ tty_lock();
+ tmp.type = state->type;
+ tmp.line = state->line;
+ tmp.port = state->port;
+@@ -1083,7 +1083,7 @@ static int get_serial_info(struct async_
+ tmp.close_delay = state->close_delay;
+ tmp.closing_wait = state->closing_wait;
+ tmp.custom_divisor = state->custom_divisor;
+- unlock_kernel();
++ tty_unlock();
+ if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+@@ -1100,14 +1100,14 @@ static int set_serial_info(struct async_
+ if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+ return -EFAULT;
+
+- lock_kernel();
++ tty_lock();
+ state = info->state;
+ old_state = *state;
+
+ change_irq = new_serial.irq != state->irq;
+ change_port = (new_serial.port != state->port);
+ if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size)) {
+- unlock_kernel();
++ tty_unlock();
+ return -EINVAL;
+ }
+
+@@ -1127,7 +1127,7 @@ static int set_serial_info(struct async_
+ }
+
+ if (new_serial.baud_base < 9600) {
+- unlock_kernel();
++ tty_unlock();
+ return -EINVAL;
+ }
+
+@@ -1163,7 +1163,7 @@ check_and_exit:
+ }
+ } else
+ retval = startup(info);
+- unlock_kernel();
++ tty_unlock();
+ return retval;
+ }
+
+@@ -1538,7 +1538,7 @@ static void rs_wait_until_sent(struct tt
+
+ orig_jiffies = jiffies;
+
+- lock_kernel();
++ tty_lock_nested(); /* tty_wait_until_sent is called from lots of places */
+ /*
+ * Set the check interval to be 1/5 of the estimated time to
+ * send a single character, and make it at least 1. The check
+@@ -1579,7 +1579,7 @@ static void rs_wait_until_sent(struct tt
+ break;
+ }
+ __set_current_state(TASK_RUNNING);
+- unlock_kernel();
++ tty_unlock();
+ #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+ #endif
+--- a/drivers/char/briq_panel.c
++++ b/drivers/char/briq_panel.c
+@@ -67,15 +67,15 @@ static void set_led(char state)
+
+ static int briq_panel_open(struct inode *ino, struct file *filep)
+ {
+- lock_kernel();
++ tty_lock();
+ /* enforce single access, vfd_is_open is protected by BKL */
+ if (vfd_is_open) {
+- unlock_kernel();
++ tty_unlock();
+ return -EBUSY;
+ }
+ vfd_is_open = 1;
+
+- unlock_kernel();
++ tty_unlock();
+ return 0;
+ }
+
+--- a/drivers/char/n_hdlc.c
++++ b/drivers/char/n_hdlc.c
+@@ -598,18 +598,18 @@ static ssize_t n_hdlc_tty_read(struct tt
+ return -EFAULT;
+ }
+
+- lock_kernel();
++ tty_lock();
+
+ for (;;) {
+ if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
+- unlock_kernel();
++ tty_unlock();
+ return -EIO;
+ }
+
+ n_hdlc = tty2n_hdlc (tty);
+ if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||
+ tty != n_hdlc->tty) {
+- unlock_kernel();
++ tty_unlock();
+ return 0;
+ }
+
+@@ -619,13 +619,13 @@ static ssize_t n_hdlc_tty_read(struct tt
+
+ /* no data */
+ if (file->f_flags & O_NONBLOCK) {
+- unlock_kernel();
++ tty_unlock();
+ return -EAGAIN;
+ }
+
+ interruptible_sleep_on (&tty->read_wait);
+ if (signal_pending(current)) {
+- unlock_kernel();
++ tty_unlock();
+ return -EINTR;
+ }
+ }
+@@ -648,7 +648,7 @@ static ssize_t n_hdlc_tty_read(struct tt
+ kfree(rbuf);
+ else
+ n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf);
+- unlock_kernel();
++ tty_unlock();
+ return ret;
+
+ } /* end of n_hdlc_tty_read() */
+@@ -691,7 +691,7 @@ static ssize_t n_hdlc_tty_write(struct t
+ count = maxframe;
+ }
+
+- lock_kernel();
++ tty_lock();
+
+ add_wait_queue(&tty->write_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+@@ -731,7 +731,7 @@ static ssize_t n_hdlc_tty_write(struct t
+ n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf);
+ n_hdlc_send_frames(n_hdlc,tty);
+ }
+- unlock_kernel();
++ tty_unlock();
+ return error;
+
+ } /* end of n_hdlc_tty_write() */
+--- a/drivers/char/n_r3964.c
++++ b/drivers/char/n_r3964.c
+@@ -1067,7 +1067,7 @@ static ssize_t r3964_read(struct tty_str
+
+ TRACE_L("read()");
+
+- lock_kernel();
++ tty_lock();
+
+ pClient = findClient(pInfo, task_pid(current));
+ if (pClient) {
+@@ -1109,7 +1109,7 @@ static ssize_t r3964_read(struct tty_str
+ }
+ ret = -EPERM;
+ unlock:
+- unlock_kernel();
++ tty_unlock();
+ return ret;
+ }
+
+@@ -1158,7 +1158,7 @@ static ssize_t r3964_write(struct tty_st
+ pHeader->locks = 0;
+ pHeader->owner = NULL;
+
+- lock_kernel();
++ tty_lock();
+
+ pClient = findClient(pInfo, task_pid(current));
+ if (pClient) {
+@@ -1177,7 +1177,7 @@ static ssize_t r3964_write(struct tty_st
+ add_tx_queue(pInfo, pHeader);
+ trigger_transmit(pInfo);
+
+- unlock_kernel();
++ tty_unlock();
+
+ return 0;
+ }
+--- a/drivers/char/pty.c
++++ b/drivers/char/pty.c
+@@ -671,9 +671,9 @@ static int ptmx_open(struct inode *inode
+ {
+ int ret;
+
+- lock_kernel();
++ tty_lock();
+ ret = __ptmx_open(inode, filp);
+- unlock_kernel();
++ tty_unlock();
+ return ret;
+ }
+
+--- a/drivers/char/selection.c
++++ b/drivers/char/selection.c
+@@ -313,7 +313,7 @@ int paste_selection(struct tty_struct *t
+ struct tty_ldisc *ld;
+ DECLARE_WAITQUEUE(wait, current);
+
+- lock_kernel();
++ tty_lock_nested(); /* always called with BTM from vt_ioctl */
+
+ acquire_console_sem();
+ poke_blanked_console();
+@@ -338,6 +338,6 @@ int paste_selection(struct tty_struct *t
+ __set_current_state(TASK_RUNNING);
+
+ tty_ldisc_deref(ld);
+- unlock_kernel();
++ tty_unlock();
+ return 0;
+ }
+--- a/drivers/char/serial167.c
++++ b/drivers/char/serial167.c
+@@ -1505,7 +1505,7 @@ cy_ioctl(struct tty_struct *tty, struct
+ printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */
+ #endif
+
+- lock_kernel();
++ tty_lock();
+
+ switch (cmd) {
+ case CYGETMON:
+@@ -1561,7 +1561,7 @@ cy_ioctl(struct tty_struct *tty, struct
+ default:
+ ret_val = -ENOIOCTLCMD;
+ }
+- unlock_kernel();
++ tty_unlock();
+
+ #ifdef SERIAL_DEBUG_OTHER
+ printk("cy_ioctl done\n");
+--- a/drivers/char/sx.c
++++ b/drivers/char/sx.c
+@@ -1699,7 +1699,7 @@ static long sx_fw_ioctl(struct file *fil
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+- lock_kernel();
++ tty_lock();
+
+ sx_dprintk(SX_DEBUG_FIRMWARE, "IOCTL %x: %lx\n", cmd, arg);
+
+@@ -1848,7 +1848,7 @@ static long sx_fw_ioctl(struct file *fil
+ break;
+ }
+ out:
+- unlock_kernel();
++ tty_unlock();
+ func_exit();
+ return rc;
+ }
+@@ -1859,7 +1859,7 @@ static int sx_break(struct tty_struct *t
+ int rv;
+
+ func_enter();
+- lock_kernel();
++ tty_lock();
+
+ if (flag)
+ rv = sx_send_command(port, HS_START, -1, HS_IDLE_BREAK);
+@@ -1868,7 +1868,7 @@ static int sx_break(struct tty_struct *t
+ if (rv != 1)
+ printk(KERN_ERR "sx: couldn't send break (%x).\n",
+ read_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat)));
+- unlock_kernel();
++ tty_unlock();
+ func_exit();
+ return 0;
+ }
+@@ -1909,7 +1909,7 @@ static int sx_ioctl(struct tty_struct *t
+ /* func_enter2(); */
+
+ rc = 0;
+- lock_kernel();
++ tty_lock();
+ switch (cmd) {
+ case TIOCGSERIAL:
+ rc = gs_getserial(&port->gs, argp);
+@@ -1921,7 +1921,7 @@ static int sx_ioctl(struct tty_struct *t
+ rc = -ENOIOCTLCMD;
+ break;
+ }
+- unlock_kernel();
++ tty_unlock();
+
+ /* func_exit(); */
+ return rc;
+--- a/drivers/char/tty_io.c
++++ b/drivers/char/tty_io.c
+@@ -149,6 +149,7 @@ static long tty_compat_ioctl(struct file
+ #else
+ #define tty_compat_ioctl NULL
+ #endif
++static int __tty_fasync(int fd, struct file *filp, int on);
+ static int tty_fasync(int fd, struct file *filp, int on);
+ static void release_tty(struct tty_struct *tty, int idx);
+ static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
+@@ -483,7 +484,7 @@ EXPORT_SYMBOL_GPL(tty_wakeup);
+ * remains intact.
+ *
+ * Locking:
+- * BKL
++ * BTM
+ * redirect lock for undoing redirection
+ * file list lock for manipulating list of ttys
+ * tty_ldisc_lock from called functions
+@@ -513,8 +514,11 @@ static void do_tty_hangup(struct work_st
+ }
+ spin_unlock(&redirect_lock);
+
+- /* inuse_filps is protected by the single kernel lock */
+- lock_kernel();
++ /* inuse_filps is protected by the single tty lock,
++ this really needs to change if we want to flush the
++ workqueue with the lock held */
++ tty_lock_nested(); /* called with BTM held from pty_close and
++ others */
+ check_tty_count(tty, "do_tty_hangup");
+
+ file_list_lock();
+@@ -525,7 +529,7 @@ static void do_tty_hangup(struct work_st
+ if (filp->f_op->write != tty_write)
+ continue;
+ closecount++;
+- tty_fasync(-1, filp, 0); /* can't block */
++ __tty_fasync(-1, filp, 0); /* can't block */
+ filp->f_op = &hung_up_tty_fops;
+ }
+ file_list_unlock();
+@@ -594,7 +598,7 @@ static void do_tty_hangup(struct work_st
+ */
+ set_bit(TTY_HUPPED, &tty->flags);
+ tty_ldisc_enable(tty);
+- unlock_kernel();
++ tty_unlock();
+ if (f)
+ fput(f);
+ }
+@@ -696,7 +700,8 @@ static void session_clear_tty(struct pid
+ * exiting; it is 0 if called by the ioctl TIOCNOTTY.
+ *
+ * Locking:
+- * BKL is taken for hysterical raisins
++ * BTM is taken for hysterical raisins, and held when
++ * called from no_tty().
+ * tty_mutex is taken to protect tty
+ * ->siglock is taken to protect ->signal/->sighand
+ * tasklist_lock is taken to walk process list for sessions
+@@ -714,10 +719,10 @@ void disassociate_ctty(int on_exit)
+ tty = get_current_tty();
+ if (tty) {
+ tty_pgrp = get_pid(tty->pgrp);
+- lock_kernel();
++ tty_lock_nested(); /* see above */
+ if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
+ tty_vhangup(tty);
+- unlock_kernel();
++ tty_unlock();
+ tty_kref_put(tty);
+ } else if (on_exit) {
+ struct pid *old_pgrp;
+@@ -774,9 +779,9 @@ void disassociate_ctty(int on_exit)
+ void no_tty(void)
+ {
+ struct task_struct *tsk = current;
+- lock_kernel();
++ tty_lock();
+ disassociate_ctty(0);
+- unlock_kernel();
++ tty_unlock();
+ proc_clear_tty(tsk);
+ }
+
+@@ -1013,19 +1018,19 @@ out:
+ * We don't put it into the syslog queue right now maybe in the future if
+ * really needed.
+ *
+- * We must still hold the BKL and test the CLOSING flag for the moment.
++ * We must still hold the BTM and test the CLOSING flag for the moment.
+ */
+
+ void tty_write_message(struct tty_struct *tty, char *msg)
+ {
+ if (tty) {
+ mutex_lock(&tty->atomic_write_lock);
+- lock_kernel();
++ tty_lock();
+ if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
+- unlock_kernel();
++ tty_unlock();
+ tty->ops->write(tty, msg, strlen(msg));
+ } else
+- unlock_kernel();
++ tty_unlock();
+ tty_write_unlock(tty);
+ }
+ return;
+@@ -1208,18 +1213,18 @@ static int tty_driver_install_tty(struct
+ int ret;
+
+ if (driver->ops->install) {
+- lock_kernel();
++ tty_lock_nested(); /* already called with BTM held */
+ ret = driver->ops->install(driver, tty);
+- unlock_kernel();
++ tty_unlock();
+ return ret;
+ }
+
+ if (tty_init_termios(tty) == 0) {
+- lock_kernel();
++ tty_lock_nested();
+ tty_driver_kref_get(driver);
+ tty->count++;
+ driver->ttys[idx] = tty;
+- unlock_kernel();
++ tty_unlock();
+ return 0;
+ }
+ return -ENOMEM;
+@@ -1312,14 +1317,15 @@ struct tty_struct *tty_init_dev(struct t
+ struct tty_struct *tty;
+ int retval;
+
+- lock_kernel();
++ tty_lock_nested(); /* always called with tty lock held already */
++
+ /* Check if pty master is being opened multiple times */
+ if (driver->subtype == PTY_TYPE_MASTER &&
+ (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
+- unlock_kernel();
++ tty_unlock();
+ return ERR_PTR(-EIO);
+ }
+- unlock_kernel();
++ tty_unlock();
+
+ /*
+ * First time open is complex, especially for PTY devices.
+@@ -1363,9 +1369,9 @@ release_mem_out:
+ if (printk_ratelimit())
+ printk(KERN_INFO "tty_init_dev: ldisc open failed, "
+ "clearing slot %d\n", idx);
+- lock_kernel();
++ tty_lock_nested();
+ release_tty(tty, idx);
+- unlock_kernel();
++ tty_unlock();
+ return ERR_PTR(retval);
+ }
+
+@@ -1512,10 +1518,10 @@ int tty_release(struct inode *inode, str
+ if (tty_paranoia_check(tty, inode, "tty_release_dev"))
+ return 0;
+
+- lock_kernel();
++ tty_lock();
+ check_tty_count(tty, "tty_release_dev");
+
+- tty_fasync(-1, filp, 0);
++ __tty_fasync(-1, filp, 0);
+
+ idx = tty->index;
+ pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+@@ -1527,18 +1533,18 @@ int tty_release(struct inode *inode, str
+ if (idx < 0 || idx >= tty->driver->num) {
+ printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
+ "free (%s)\n", tty->name);
+- unlock_kernel();
++ tty_unlock();
+ return 0;
+ }
+ if (!devpts) {
+ if (tty != tty->driver->ttys[idx]) {
+- unlock_kernel();
++ tty_unlock();
+ printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
+ "for (%s)\n", idx, tty->name);
+ return 0;
+ }
+ if (tty->termios != tty->driver->termios[idx]) {
+- unlock_kernel();
++ tty_unlock();
+ printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
+ "for (%s)\n",
+ idx, tty->name);
+@@ -1556,21 +1562,21 @@ int tty_release(struct inode *inode, str
+ if (tty->driver->other &&
+ !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
+ if (o_tty != tty->driver->other->ttys[idx]) {
+- unlock_kernel();
++ tty_unlock();
+ printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
+ "not o_tty for (%s)\n",
+ idx, tty->name);
+ return 0 ;
+ }
+ if (o_tty->termios != tty->driver->other->termios[idx]) {
+- unlock_kernel();
++ tty_unlock();
+ printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
+ "not o_termios for (%s)\n",
+ idx, tty->name);
+ return 0;
+ }
+ if (o_tty->link != tty) {
+- unlock_kernel();
++ tty_unlock();
+ printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
+ return 0;
+ }
+@@ -1579,7 +1585,7 @@ int tty_release(struct inode *inode, str
+ if (tty->ops->close)
+ tty->ops->close(tty, filp);
+
+- unlock_kernel();
++ tty_unlock();
+ /*
+ * Sanity check: if tty->count is going to zero, there shouldn't be
+ * any waiters on tty->read_wait or tty->write_wait. We test the
+@@ -1602,7 +1608,7 @@ int tty_release(struct inode *inode, str
+ opens on /dev/tty */
+
+ mutex_lock(&tty_mutex);
+- lock_kernel();
++ tty_lock();
+ tty_closing = tty->count <= 1;
+ o_tty_closing = o_tty &&
+ (o_tty->count <= (pty_master ? 1 : 0));
+@@ -1633,7 +1639,7 @@ int tty_release(struct inode *inode, str
+
+ printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
+ "active!\n", tty_name(tty, buf));
+- unlock_kernel();
++ tty_unlock();
+ mutex_unlock(&tty_mutex);
+ schedule();
+ }
+@@ -1698,7 +1704,7 @@ int tty_release(struct inode *inode, str
+
+ /* check whether both sides are closing ... */
+ if (!tty_closing || (o_tty && !o_tty_closing)) {
+- unlock_kernel();
++ tty_unlock();
+ return 0;
+ }
+
+@@ -1718,7 +1724,7 @@ int tty_release(struct inode *inode, str
+ /* Make this pty number available for reallocation */
+ if (devpts)
+ devpts_kill_index(inode, idx);
+- unlock_kernel();
++ tty_unlock();
+ return 0;
+ }
+
+@@ -1760,12 +1766,12 @@ retry_open:
+ retval = 0;
+
+ mutex_lock(&tty_mutex);
+- lock_kernel();
++ tty_lock();
+
+ if (device == MKDEV(TTYAUX_MAJOR, 0)) {
+ tty = get_current_tty();
+ if (!tty) {
+- unlock_kernel();
++ tty_unlock();
+ mutex_unlock(&tty_mutex);
+ return -ENXIO;
+ }
+@@ -1797,14 +1803,14 @@ retry_open:
+ goto got_driver;
+ }
+ }
+- unlock_kernel();
++ tty_unlock();
+ mutex_unlock(&tty_mutex);
+ return -ENODEV;
+ }
+
+ driver = get_tty_driver(device, &index);
+ if (!driver) {
+- unlock_kernel();
++ tty_unlock();
+ mutex_unlock(&tty_mutex);
+ return -ENODEV;
+ }
+@@ -1814,7 +1820,7 @@ got_driver:
+ tty = tty_driver_lookup_tty(driver, inode, index);
+
+ if (IS_ERR(tty)) {
+- unlock_kernel();
++ tty_unlock();
+ mutex_unlock(&tty_mutex);
+ return PTR_ERR(tty);
+ }
+@@ -1830,7 +1836,7 @@ got_driver:
+ mutex_unlock(&tty_mutex);
+ tty_driver_kref_put(driver);
+ if (IS_ERR(tty)) {
+- unlock_kernel();
++ tty_unlock();
+ return PTR_ERR(tty);
+ }
+
+@@ -1862,11 +1868,11 @@ got_driver:
+ #endif
+ tty_release(inode, filp);
+ if (retval != -ERESTARTSYS) {
+- unlock_kernel();
++ tty_unlock();
+ return retval;
+ }
+ if (signal_pending(current)) {
+- unlock_kernel();
++ tty_unlock();
+ return retval;
+ }
+ schedule();
+@@ -1875,14 +1881,14 @@ got_driver:
+ */
+ if (filp->f_op == &hung_up_tty_fops)
+ filp->f_op = &tty_fops;
+- unlock_kernel();
++ tty_unlock();
+ goto retry_open;
+ }
+- unlock_kernel();
++ tty_unlock();
+
+
+ mutex_lock(&tty_mutex);
+- lock_kernel();
++ tty_lock();
+ spin_lock_irq(&current->sighand->siglock);
+ if (!noctty &&
+ current->signal->leader &&
+@@ -1890,7 +1896,7 @@ got_driver:
+ tty->session == NULL)
+ __proc_set_tty(current, tty);
+ spin_unlock_irq(&current->sighand->siglock);
+- unlock_kernel();
++ tty_unlock();
+ mutex_unlock(&tty_mutex);
+ return 0;
+ }
+@@ -1926,13 +1932,12 @@ static unsigned int tty_poll(struct file
+ return ret;
+ }
+
+-static int tty_fasync(int fd, struct file *filp, int on)
++static int __tty_fasync(int fd, struct file *filp, int on)
+ {
+ struct tty_struct *tty;
+ unsigned long flags;
+ int retval = 0;
+
+- lock_kernel();
+ tty = (struct tty_struct *)filp->private_data;
+ if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync"))
+ goto out;
+@@ -1966,7 +1971,15 @@ static int tty_fasync(int fd, struct fil
+ }
+ retval = 0;
+ out:
+- unlock_kernel();
++ return retval;
++}
++
++static int tty_fasync(int fd, struct file *filp, int on)
++{
++ int retval;
++ tty_lock();
++ retval = __tty_fasync(fd, filp, on);
++ tty_unlock();
+ return retval;
+ }
+
+--- a/drivers/char/tty_ldisc.c
++++ b/drivers/char/tty_ldisc.c
+@@ -440,6 +440,8 @@ static void tty_set_termios_ldisc(struct
+ *
+ * A helper opening method. Also a convenient debugging and check
+ * point.
++ *
++ * Locking: always called with BTM already held.
+ */
+
+ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
+@@ -447,10 +449,10 @@ static int tty_ldisc_open(struct tty_str
+ WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
+ if (ld->ops->open) {
+ int ret;
+- /* BKL here locks verus a hangup event */
+- lock_kernel();
++ /* BTM here locks versus a hangup event */
++ tty_lock_nested(); /* always held here already */
+ ret = ld->ops->open(tty);
+- unlock_kernel();
++ tty_unlock();
+ return ret;
+ }
+ return 0;
+@@ -553,7 +555,7 @@ int tty_set_ldisc(struct tty_struct *tty
+ if (IS_ERR(new_ldisc))
+ return PTR_ERR(new_ldisc);
+
+- lock_kernel();
++ tty_lock();
+ /*
+ * We need to look at the tty locking here for pty/tty pairs
+ * when both sides try to change in parallel.
+@@ -567,12 +569,12 @@ int tty_set_ldisc(struct tty_struct *tty
+ */
+
+ if (tty->ldisc->ops->num == ldisc) {
+- unlock_kernel();
++ tty_unlock();
+ tty_ldisc_put(new_ldisc);
+ return 0;
+ }
+
+- unlock_kernel();
++ tty_unlock();
+ /*
+ * Problem: What do we do if this blocks ?
+ * We could deadlock here
+@@ -594,7 +596,7 @@ int tty_set_ldisc(struct tty_struct *tty
+ mutex_lock(&tty->ldisc_mutex);
+ }
+
+- lock_kernel();
++ tty_lock();
+
+ set_bit(TTY_LDISC_CHANGING, &tty->flags);
+
+@@ -607,7 +609,7 @@ int tty_set_ldisc(struct tty_struct *tty
+
+ o_ldisc = tty->ldisc;
+
+- unlock_kernel();
++ tty_unlock();
+ /*
+ * Make sure we don't change while someone holds a
+ * reference to the line discipline. The TTY_LDISC bit
+@@ -633,14 +635,14 @@ int tty_set_ldisc(struct tty_struct *tty
+ flush_scheduled_work();
+
+ mutex_lock(&tty->ldisc_mutex);
+- lock_kernel();
++ tty_lock();
+ if (test_bit(TTY_HUPPED, &tty->flags)) {
+ /* We were raced by the hangup method. It will have stomped
+ the ldisc data and closed the ldisc down */
+ clear_bit(TTY_LDISC_CHANGING, &tty->flags);
+ mutex_unlock(&tty->ldisc_mutex);
+ tty_ldisc_put(new_ldisc);
+- unlock_kernel();
++ tty_unlock();
+ return -EIO;
+ }
+
+@@ -682,7 +684,7 @@ int tty_set_ldisc(struct tty_struct *tty
+ if (o_work)
+ schedule_delayed_work(&o_tty->buf.work, 1);
+ mutex_unlock(&tty->ldisc_mutex);
+- unlock_kernel();
++ tty_unlock();
+ return retval;
+ }
+
+--- a/drivers/char/vc_screen.c
++++ b/drivers/char/vc_screen.c
+@@ -463,10 +463,10 @@ vcs_open(struct inode *inode, struct fil
+ unsigned int currcons = iminor(inode) & 127;
+ int ret = 0;
+
+- lock_kernel();
++ tty_lock();
+ if(currcons && !vc_cons_allocated(currcons-1))
+ ret = -ENXIO;
+- unlock_kernel();
++ tty_unlock();
+ return ret;
+ }
+
+--- a/drivers/char/vt_ioctl.c
++++ b/drivers/char/vt_ioctl.c
+@@ -509,7 +509,7 @@ int vt_ioctl(struct tty_struct *tty, str
+
+ console = vc->vc_num;
+
+- lock_kernel();
++ tty_lock();
+
+ if (!vc_cons_allocated(console)) { /* impossible? */
+ ret = -ENOIOCTLCMD;
+@@ -1336,7 +1336,7 @@ int vt_ioctl(struct tty_struct *tty, str
+ ret = -ENOIOCTLCMD;
+ }
+ out:
+- unlock_kernel();
++ tty_unlock();
+ return ret;
+ eperm:
+ ret = -EPERM;
+@@ -1503,7 +1503,7 @@ long vt_compat_ioctl(struct tty_struct *
+
+ console = vc->vc_num;
+
+- lock_kernel();
++ tty_lock();
+
+ if (!vc_cons_allocated(console)) { /* impossible? */
+ ret = -ENOIOCTLCMD;
+@@ -1571,11 +1571,11 @@ long vt_compat_ioctl(struct tty_struct *
+ goto fallback;
+ }
+ out:
+- unlock_kernel();
++ tty_unlock();
+ return ret;
+
+ fallback:
+- unlock_kernel();
++ tty_unlock();
+ return vt_ioctl(tty, file, cmd, arg);
+ }
+
+--- a/drivers/serial/68360serial.c
++++ b/drivers/serial/68360serial.c
+@@ -1705,7 +1705,7 @@ static void rs_360_wait_until_sent(struc
+ printk("jiff=%lu...", jiffies);
+ #endif
+
+- lock_kernel();
++ tty_lock_nested(); /* always held already since we come from ->close */
+ /* We go through the loop at least once because we can't tell
+ * exactly when the last character exits the shifter. There can
+ * be at least two characters waiting to be sent after the buffers
+@@ -1734,7 +1734,7 @@ static void rs_360_wait_until_sent(struc
+ bdp--;
+ } while (bdp->status & BD_SC_READY);
+ current->state = TASK_RUNNING;
+- unlock_kernel();
++ tty_unlock();
+ #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+ #endif
+--- a/drivers/serial/crisv10.c
++++ b/drivers/serial/crisv10.c
+@@ -3924,7 +3924,7 @@ static void rs_wait_until_sent(struct tt
+ * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO
+ * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k)
+ */
+- lock_kernel();
++ tty_lock_nested(); /* locked already when coming from close */
+ orig_jiffies = jiffies;
+ while (info->xmit.head != info->xmit.tail || /* More in send queue */
+ (*info->ostatusadr & 0x007f) || /* more in FIFO */
+@@ -3941,7 +3941,7 @@ static void rs_wait_until_sent(struct tt
+ curr_time_usec - info->last_tx_active_usec;
+ }
+ set_current_state(TASK_RUNNING);
+- unlock_kernel();
++ tty_unlock();
+ }
+
+ /*
+--- a/drivers/serial/serial_core.c
++++ b/drivers/serial/serial_core.c
+@@ -1274,7 +1274,7 @@ static void uart_close(struct tty_struct
+ struct uart_port *uport;
+ unsigned long flags;
+
+- BUG_ON(!kernel_locked());
++ BUG_ON(!tty_locked());
+
+ if (!state)
+ return;
+@@ -1382,7 +1382,7 @@ static void uart_wait_until_sent(struct
+ if (port->type == PORT_UNKNOWN || port->fifosize == 0)
+ return;
+
+- lock_kernel();
++ tty_lock_nested(); /* already locked when coming from close */
+
+ /*
+ * Set the check interval to be 1/5 of the estimated time to
+@@ -1429,7 +1429,7 @@ static void uart_wait_until_sent(struct
+ break;
+ }
+ set_current_state(TASK_RUNNING); /* might not be needed */
+- unlock_kernel();
++ tty_unlock();
+ }
+
+ /*
+@@ -1444,7 +1444,7 @@ static void uart_hangup(struct tty_struc
+ struct tty_port *port = &state->port;
+ unsigned long flags;
+
+- BUG_ON(!kernel_locked());
++ BUG_ON(!tty_locked());
+ pr_debug("uart_hangup(%d)\n", state->uart_port->line);
+
+ mutex_lock(&port->mutex);
+@@ -1570,7 +1570,7 @@ static int uart_open(struct tty_struct *
+ struct tty_port *port;
+ int retval, line = tty->index;
+
+- BUG_ON(!kernel_locked());
++ BUG_ON(!tty_locked());
+ pr_debug("uart_open(%d) called\n", line);
+
+ /*
+--- a/drivers/video/console/vgacon.c
++++ b/drivers/video/console/vgacon.c
+@@ -1108,7 +1108,7 @@ static int vgacon_do_font_op(struct vgas
+ charmap += 4 * cmapsz;
+ #endif
+
+- unlock_kernel();
++ tty_unlock();
+ spin_lock_irq(&vga_lock);
+ /* First, the Sequencer */
+ vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
+@@ -1192,7 +1192,7 @@ static int vgacon_do_font_op(struct vgas
+ vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);
+ }
+ spin_unlock_irq(&vga_lock);
+- lock_kernel();
++ tty_lock();
+ return 0;
+ }
+
+--- a/include/linux/tty.h
++++ b/include/linux/tty.h
+@@ -13,6 +13,7 @@
+ #include <linux/tty_driver.h>
+ #include <linux/tty_ldisc.h>
+ #include <linux/mutex.h>
++#include <linux/smp_lock.h>
+
+ #include <asm/system.h>
+
+@@ -572,5 +573,35 @@ extern int vt_ioctl(struct tty_struct *t
+ extern long vt_compat_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg);
+
++/* functions for preparation of BKL removal */
++
++/*
++ * tty_lock_nested get the tty_lock while potentially holding it
++ *
++ * The Big TTY Mutex is a recursive lock, meaning you can take it
++ * from a thread that is already holding it.
++ * This is bad for a number of reasons, so tty_lock_nested should
++ * really be used as rarely as possible. If a code location can
++ * be shown to never get called with this held already, it should
++ * use tty_lock() instead.
++ */
++static inline void __lockfunc tty_lock_nested(void) __acquires(kernel_lock)
++{
++ lock_kernel();
++}
++static inline void tty_lock(void) __acquires(kernel_lock)
++{
++#ifdef CONFIG_LOCK_KERNEL
++ /* kernel_locked is 1 for !CONFIG_LOCK_KERNEL */
++ WARN_ON(kernel_locked());
++#endif
++ lock_kernel();
++}
++static inline void tty_unlock(void) __releases(kernel_lock)
++{
++ unlock_kernel();
++}
++#define tty_locked() (kernel_locked())
++
+ #endif /* __KERNEL__ */
+ #endif
diff --git a/tty/tty-untangle-locking-of-wait_until_sent.patch b/tty/tty-untangle-locking-of-wait_until_sent.patch
new file mode 100644
index 00000000000000..da72b6ed9d6e02
--- /dev/null
+++ b/tty/tty-untangle-locking-of-wait_until_sent.patch
@@ -0,0 +1,175 @@
+From arnd@arndb.de Wed Jun 16 13:45:16 2010
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Tue, 1 Jun 2010 22:53:07 +0200
+Subject: tty: untangle locking of wait_until_sent
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>
+Message-ID: <1275425591-8803-28-git-send-email-arnd@arndb.de>
+
+
+Some wait_until_sent versions require the big
+tty mutex, others don't and some callers of
+wait_until_sent already hold it while other don't.
+That leads to recursive use of the BTM in these
+functions, which we're trying to get rid of.
+
+This turns all cleans up the locking there so
+that the driver's wait_until_sent function
+never takes the BTM itself if it is already
+called with that lock held.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/amiserial.c | 11 +++++++++--
+ drivers/serial/68360serial.c | 2 --
+ drivers/serial/crisv10.c | 2 --
+ drivers/serial/serial_core.c | 31 ++++++++++++++++++++++---------
+ 4 files changed, 31 insertions(+), 15 deletions(-)
+
+--- a/drivers/char/amiserial.c
++++ b/drivers/char/amiserial.c
+@@ -1528,6 +1528,7 @@ static void rs_wait_until_sent(struct tt
+ {
+ struct async_struct * info = tty->driver_data;
+ unsigned long orig_jiffies, char_time;
++ int tty_was_locked = tty_locked();
+ int lsr;
+
+ if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
+@@ -1538,7 +1539,12 @@ static void rs_wait_until_sent(struct tt
+
+ orig_jiffies = jiffies;
+
+- tty_lock_nested(); /* tty_wait_until_sent is called from lots of places */
++ /*
++ * tty_wait_until_sent is called from lots of places,
++ * with or without the BTM.
++ */
++ if (!tty_was_locked)
++ tty_lock();
+ /*
+ * Set the check interval to be 1/5 of the estimated time to
+ * send a single character, and make it at least 1. The check
+@@ -1579,7 +1585,8 @@ static void rs_wait_until_sent(struct tt
+ break;
+ }
+ __set_current_state(TASK_RUNNING);
+- tty_unlock();
++ if (!tty_was_locked)
++ tty_unlock();
+ #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+ #endif
+--- a/drivers/serial/68360serial.c
++++ b/drivers/serial/68360serial.c
+@@ -1705,7 +1705,6 @@ static void rs_360_wait_until_sent(struc
+ printk("jiff=%lu...", jiffies);
+ #endif
+
+- tty_lock_nested(); /* always held already since we come from ->close */
+ /* We go through the loop at least once because we can't tell
+ * exactly when the last character exits the shifter. There can
+ * be at least two characters waiting to be sent after the buffers
+@@ -1734,7 +1733,6 @@ static void rs_360_wait_until_sent(struc
+ bdp--;
+ } while (bdp->status & BD_SC_READY);
+ current->state = TASK_RUNNING;
+- tty_unlock();
+ #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+ #endif
+--- a/drivers/serial/crisv10.c
++++ b/drivers/serial/crisv10.c
+@@ -3924,7 +3924,6 @@ static void rs_wait_until_sent(struct tt
+ * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO
+ * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k)
+ */
+- tty_lock_nested(); /* locked already when coming from close */
+ orig_jiffies = jiffies;
+ while (info->xmit.head != info->xmit.tail || /* More in send queue */
+ (*info->ostatusadr & 0x007f) || /* more in FIFO */
+@@ -3941,7 +3940,6 @@ static void rs_wait_until_sent(struct tt
+ curr_time_usec - info->last_tx_active_usec;
+ }
+ set_current_state(TASK_RUNNING);
+- tty_unlock();
+ }
+
+ /*
+--- a/drivers/serial/serial_core.c
++++ b/drivers/serial/serial_core.c
+@@ -60,7 +60,7 @@ static struct lock_class_key port_lock_k
+
+ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
+ struct ktermios *old_termios);
+-static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
++static void __uart_wait_until_sent(struct uart_port *port, int timeout);
+ static void uart_change_pm(struct uart_state *state, int pm_state);
+
+ /*
+@@ -1322,8 +1322,16 @@ static void uart_close(struct tty_struct
+ tty->closing = 1;
+ spin_unlock_irqrestore(&port->lock, flags);
+
+- if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+- tty_wait_until_sent(tty, msecs_to_jiffies(port->closing_wait));
++ if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
++ /*
++ * hack: open-coded tty_wait_until_sent to avoid
++ * recursive tty_lock
++ */
++ long timeout = msecs_to_jiffies(port->closing_wait);
++ if (wait_event_interruptible_timeout(tty->write_wait,
++ !tty_chars_in_buffer(tty), timeout) >= 0)
++ __uart_wait_until_sent(uport, timeout);
++ }
+
+ /*
+ * At this point, we stop accepting input. To do this, we
+@@ -1339,7 +1347,7 @@ static void uart_close(struct tty_struct
+ * has completely drained; this is especially
+ * important if there is a transmit FIFO!
+ */
+- uart_wait_until_sent(tty, uport->timeout);
++ __uart_wait_until_sent(uport, uport->timeout);
+ }
+
+ uart_shutdown(tty, state);
+@@ -1373,17 +1381,13 @@ done:
+ mutex_unlock(&port->mutex);
+ }
+
+-static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
++static void __uart_wait_until_sent(struct uart_port *port, int timeout)
+ {
+- struct uart_state *state = tty->driver_data;
+- struct uart_port *port = state->uart_port;
+ unsigned long char_time, expire;
+
+ if (port->type == PORT_UNKNOWN || port->fifosize == 0)
+ return;
+
+- tty_lock_nested(); /* already locked when coming from close */
+-
+ /*
+ * Set the check interval to be 1/5 of the estimated time to
+ * send a single character, and make it at least 1. The check
+@@ -1429,6 +1433,15 @@ static void uart_wait_until_sent(struct
+ break;
+ }
+ set_current_state(TASK_RUNNING); /* might not be needed */
++}
++
++static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
++{
++ struct uart_state *state = tty->driver_data;
++ struct uart_port *port = state->uart_port;
++
++ tty_lock();
++ __uart_wait_until_sent(port, timeout);
+ tty_unlock();
+ }
+
diff --git a/tty/vc-locking-clean-up.patch b/tty/vc-locking-clean-up.patch
new file mode 100644
index 00000000000000..866122ce1597f2
--- /dev/null
+++ b/tty/vc-locking-clean-up.patch
@@ -0,0 +1,81 @@
+From arnd@arndb.de Wed Jun 16 13:30:44 2010
+From: Alan Cox <alan@linux.intel.com>
+Date: Tue, 1 Jun 2010 22:52:54 +0200
+Subject: vc: Locking clean up
+To: Greg KH <gregkh@suse.de>
+Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>, Alan Cox <alan@lxorguk.ukuu.org.uk>, Frederic Weisbecker <fweisbec@gmail.com>, John Kacur <jkacur@redhat.com>, Alan Cox <alan@linux.intel.com>
+Message-ID: <1275425591-8803-15-git-send-email-arnd@arndb.de>
+
+
+From: Alan Cox <alan@linux.intel.com>
+
+The virtual console layer uses the BKL for various things that don't really
+need it. Clean them out.
+
+Signed-off-by: Alan Cox <alan@linux.intel.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/selection.c | 4 ++++
+ drivers/char/vt.c | 7 ++++---
+ 2 files changed, 8 insertions(+), 3 deletions(-)
+
+--- a/drivers/char/selection.c
++++ b/drivers/char/selection.c
+@@ -26,6 +26,7 @@
+ #include <linux/selection.h>
+ #include <linux/tiocl.h>
+ #include <linux/console.h>
++#include <linux/smp_lock.h>
+
+ /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
+ #define isspace(c) ((c) == ' ')
+@@ -312,6 +313,8 @@ int paste_selection(struct tty_struct *t
+ struct tty_ldisc *ld;
+ DECLARE_WAITQUEUE(wait, current);
+
++ lock_kernel();
++
+ acquire_console_sem();
+ poke_blanked_console();
+ release_console_sem();
+@@ -335,5 +338,6 @@ int paste_selection(struct tty_struct *t
+ __set_current_state(TASK_RUNNING);
+
+ tty_ldisc_deref(ld);
++ unlock_kernel();
+ return 0;
+ }
+--- a/drivers/char/vt.c
++++ b/drivers/char/vt.c
+@@ -281,8 +281,12 @@ static inline unsigned short *screenpos(
+ return p;
+ }
+
++/* Called from the keyboard irq path.. */
+ static inline void scrolldelta(int lines)
+ {
++ /* FIXME */
++ /* scrolldelta needs some kind of consistency lock, but the BKL was
++ and still is not protecting versus the scheduled back end */
+ scrollback_delta += lines;
+ schedule_console_callback();
+ }
+@@ -2605,8 +2609,6 @@ int tioclinux(struct tty_struct *tty, un
+ return -EFAULT;
+ ret = 0;
+
+- lock_kernel();
+-
+ switch (type)
+ {
+ case TIOCL_SETSEL:
+@@ -2681,7 +2683,6 @@ int tioclinux(struct tty_struct *tty, un
+ ret = -EINVAL;
+ break;
+ }
+- unlock_kernel();
+ return ret;
+ }
+
diff --git a/tty/vt-clean-up-the-code-use-kernel-library.patch b/tty/vt-clean-up-the-code-use-kernel-library.patch
new file mode 100644
index 00000000000000..ebdb7353978d2b
--- /dev/null
+++ b/tty/vt-clean-up-the-code-use-kernel-library.patch
@@ -0,0 +1,41 @@
+From andy.shevchenko@gmail.com Wed Jun 16 13:22:07 2010
+From: Andy Shevchenko <andy.shevchenko@gmail.com>
+Date: Tue, 15 Jun 2010 17:24:16 +0300
+Subject: vt: clean up the code - use kernel library
+To: linux-kernel@vger.kernel.org
+Cc: Andy Shevchenko <ext-andriy.shevchenko@nokia.com>, Andrew Morton <akpm@linux-foundation.org>, Greg Kroah-Hartman <gregkh@suse.de>, Alan Cox <alan@linux.intel.com>
+Message-ID: <1276611856-28232-1-git-send-email-andy.shevchenko@gmail.com>
+
+
+From: Andy Shevchenko <ext-andriy.shevchenko@nokia.com>
+
+Signed-off-by: Andy Shevchenko <ext-andriy.shevchenko@nokia.com>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: Alan Cox <alan@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/vt.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/char/vt.c
++++ b/drivers/char/vt.c
+@@ -104,6 +104,7 @@
+ #include <linux/io.h>
+ #include <asm/system.h>
+ #include <linux/uaccess.h>
++#include <linux/ctype.h>
+
+ #define MAX_NR_CON_DRIVER 16
+
+@@ -1789,8 +1790,8 @@ static void do_con_trol(struct tty_struc
+ vc->vc_state = ESnormal;
+ return;
+ case ESpalette:
+- if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
+- vc->vc_par[vc->vc_npar++] = (c > '9' ? (c & 0xDF) - 'A' + 10 : c - '0');
++ if (isxdigit(c)) {
++ vc->vc_par[vc->vc_npar++] = hex_to_bin(c);
+ if (vc->vc_npar == 7) {
+ int i = vc->vc_par[0] * 3, j = 1;
+ vc->vc_palette[i] = 16 * vc->vc_par[j++];
diff --git a/usb.current/usb-ehci-mxc-bail-out-on-transceiver-problems.patch b/usb.current/usb-ehci-mxc-bail-out-on-transceiver-problems.patch
new file mode 100644
index 00000000000000..1d6323fefa3830
--- /dev/null
+++ b/usb.current/usb-ehci-mxc-bail-out-on-transceiver-problems.patch
@@ -0,0 +1,69 @@
+From w.sang@pengutronix.de Wed Jun 16 13:24:59 2010
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Tue, 15 Jun 2010 12:34:23 +0200
+Subject: USB: ehci-mxc: bail out on transceiver problems
+To: linux-usb@vger.kernel.org
+Cc: linux-arm-kernel@lists.infradead.org, Wolfram Sang <w.sang@pengutronix.de>, Sascha Hauer <s.hauer@pengutronix.de>, Daniel Mack <daniel@caiaq.de>, Greg KH <gregkh@suse.de>, stable@kernel.org
+Message-ID: <1276598063-3956-2-git-send-email-w.sang@pengutronix.de>
+
+
+The old code registered the hcd even if there were no transceivers
+detected, leading to oopses like this if we try to probe a non-existant
+ULPI:
+
+[ 2.730000] mxc-ehci mxc-ehci.0: unable to init transceiver
+[ 2.740000] timeout polling for ULPI device
+[ 2.740000] timeout polling for ULPI device
+[ 2.750000] mxc-ehci mxc-ehci.0: unable to enable vbus on transceiver
+[ 2.750000] mxc-ehci mxc-ehci.0: Freescale On-Chip EHCI Host Controller
+[ 2.760000] mxc-ehci mxc-ehci.0: new USB bus registered, assigned bus number 2
+[ 2.770000] Unhandled fault: external abort on non-linefetch (0x808) at 0xc4876184
+[ 2.770000] Internal error: : 808 [#1] PREEMPT
+[ 2.770000] last sysfs file:
+[ 2.770000] Modules linked in:
+[ 2.770000] CPU: 0 Not tainted (2.6.33.5 #5)
+[ 2.770000] PC is at ehci_hub_control+0x4d4/0x8f8
+[ 2.770000] LR is at ehci_mxc_setup+0xbc/0xdc
+[ 2.770000] pc : [<c0196dfc>] lr : [<c019bc8c>] psr: 00000093
+[ 2.770000] sp : c3815e40 ip : 00000001 fp : 60000013
+[ 2.770000] r10: c4876184 r9 : 00000000 r8 : c3814000
+[ 2.770000] r7 : c391d2cc r6 : 00000001 r5 : 00000001 r4 : 00000000
+[ 2.770000] r3 : 80000000 r2 : 00000007 r1 : 80000000 r0 : c4876184
+[ 2.770000] Flags: nzcv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel
+[ 2.770000] Control: 0005317f Table: a0004000 DAC: 00000017
+[ 2.770000] Process swapper (pid: 1, stack limit = 0xc3814270)
+...
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Cc: Sascha Hauer <s.hauer@pengutronix.de>
+Cc: stable <stable@kernel.org>
+Acked-by: Daniel Mack <daniel@caiaq.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ehci-mxc.c | 13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/host/ehci-mxc.c
++++ b/drivers/usb/host/ehci-mxc.c
+@@ -207,10 +207,17 @@ static int ehci_mxc_drv_probe(struct pla
+ /* Initialize the transceiver */
+ if (pdata->otg) {
+ pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;
+- if (otg_init(pdata->otg) != 0)
+- dev_err(dev, "unable to init transceiver\n");
+- else if (otg_set_vbus(pdata->otg, 1) != 0)
++ ret = otg_init(pdata->otg);
++ if (ret) {
++ dev_err(dev, "unable to init transceiver, probably missing\n");
++ ret = -ENODEV;
++ goto err_add;
++ }
++ ret = otg_set_vbus(pdata->otg, 1);
++ if (ret) {
+ dev_err(dev, "unable to enable vbus on transceiver\n");
++ goto err_add;
++ }
+ }
+
+ priv->hcd = hcd;
diff --git a/usb.current/usb-musb-fix-a-bug-by-making-suspend-interrupt-available-in-device-mode.patch b/usb.current/usb-musb-fix-a-bug-by-making-suspend-interrupt-available-in-device-mode.patch
new file mode 100644
index 00000000000000..bca576b6d5aa45
--- /dev/null
+++ b/usb.current/usb-musb-fix-a-bug-by-making-suspend-interrupt-available-in-device-mode.patch
@@ -0,0 +1,49 @@
+From x0082077@ti.com Wed Jun 16 13:23:21 2010
+From: Maulik Mankad <x0082077@ti.com>
+Date: Tue, 15 Jun 2010 14:40:27 +0530
+Subject: usb: musb: Fix a bug by making suspend interrupt available in device mode
+To: linux-usb@vger.kernel.org
+Cc: Maulik Mankad <x0082077@ti.com>, David Brownell <david-b@pacbell.net>, Felipe Balbi <felipe.balbi@nokia.com>
+Message-ID: <1276593027-30168-1-git-send-email-x0082077@ti.com>
+
+
+As a part of aligning the ISR code for MUSB with the specs, the
+ISR code was re-written.
+
+See Commit 1c25fda4a09e8229800979986ef399401053b46e (usb: musb: handle
+irqs in the order dictated by programming guide)
+
+With this the suspend interrupt came accidently under CONFIG_USB_MUSB_HDRC_HCD.
+
+The fix brings suspend interrupt handling outside
+CONFIG_USB_MUSB_HDRC_HCD.
+
+Signed-off-by: Maulik Mankad <x0082077@ti.com>
+Cc: David Brownell <david-b@pacbell.net>
+Acked-by: Felipe Balbi <felipe.balbi@nokia.com>
+Cc: stable <stable@kernel.org> [.34]
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/musb/musb_core.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/musb/musb_core.c
++++ b/drivers/usb/musb/musb_core.c
+@@ -642,7 +642,7 @@ static irqreturn_t musb_stage0_irq(struc
+ handled = IRQ_HANDLED;
+ }
+
+-
++#endif
+ if (int_usb & MUSB_INTR_SUSPEND) {
+ DBG(1, "SUSPEND (%s) devctl %02x power %02x\n",
+ otg_state_string(musb), devctl, power);
+@@ -705,6 +705,7 @@ static irqreturn_t musb_stage0_irq(struc
+ }
+ }
+
++#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ if (int_usb & MUSB_INTR_CONNECT) {
+ struct usb_hcd *hcd = musb_to_hcd(musb);
+ void __iomem *mbase = musb->mregs;
diff --git a/usb.current/usb-otg-ulpi-bail-out-on-read-errors.patch b/usb.current/usb-otg-ulpi-bail-out-on-read-errors.patch
new file mode 100644
index 00000000000000..733b614dacb4dc
--- /dev/null
+++ b/usb.current/usb-otg-ulpi-bail-out-on-read-errors.patch
@@ -0,0 +1,46 @@
+From w.sang@pengutronix.de Wed Jun 16 13:24:08 2010
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Tue, 15 Jun 2010 12:34:22 +0200
+Subject: USB: otg/ulpi: bail out on read errors
+To: linux-usb@vger.kernel.org
+Cc: linux-arm-kernel@lists.infradead.org, Wolfram Sang <w.sang@pengutronix.de>, Sascha Hauer <s.hauer@pengutronix.de>, Daniel Mack <daniel@caiaq.de>, Greg KH <gregkh@suse.de>
+Message-ID: <1276598063-3956-1-git-send-email-w.sang@pengutronix.de>
+
+otg_read may return errnos, so bail out correctly to prevent bogus
+ID-numbers.
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Cc: Sascha Hauer <s.hauer@pengutronix.de>
+Acked-by: Daniel Mack <daniel@caiaq.de>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/otg/ulpi.c | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/otg/ulpi.c
++++ b/drivers/usb/otg/ulpi.c
+@@ -59,12 +59,17 @@ static int ulpi_set_flags(struct otg_tra
+
+ static int ulpi_init(struct otg_transceiver *otg)
+ {
+- int i, vid, pid;
++ int i, vid, pid, ret;
++ u32 ulpi_id = 0;
+
+- vid = (otg_io_read(otg, ULPI_VENDOR_ID_HIGH) << 8) |
+- otg_io_read(otg, ULPI_VENDOR_ID_LOW);
+- pid = (otg_io_read(otg, ULPI_PRODUCT_ID_HIGH) << 8) |
+- otg_io_read(otg, ULPI_PRODUCT_ID_LOW);
++ for (i = 0; i < 4; i++) {
++ ret = otg_io_read(otg, ULPI_PRODUCT_ID_HIGH - i);
++ if (ret < 0)
++ return ret;
++ ulpi_id = (ulpi_id << 8) | ret;
++ }
++ vid = ulpi_id & 0xffff;
++ pid = ulpi_id >> 16;
+
+ pr_info("ULPI transceiver vendor/product ID 0x%04x/0x%04x\n", vid, pid);
+
diff --git a/usb/revert-usb-adding-support-for-htc-smartphones-to-ipaq.patch b/usb/revert-usb-adding-support-for-htc-smartphones-to-ipaq.patch
new file mode 100644
index 00000000000000..840cce4f42565f
--- /dev/null
+++ b/usb/revert-usb-adding-support-for-htc-smartphones-to-ipaq.patch
@@ -0,0 +1,35 @@
+From leann.ogasawara@canonical.com Wed Jun 16 13:29:49 2010
+From: Leann Ogasawara <leann.ogasawara@canonical.com>
+Date: Thu, 10 Jun 2010 15:49:24 -0700
+Subject: Revert "USB: Adding support for HTC Smartphones to ipaq"
+To: gregkh <gregkh@suse.de>
+Cc: linux-usb <linux-usb@vger.kernel.org>
+Message-ID: <1276210164.1221.3656.camel@emiko>
+
+
+ipaq already had this device id defined:
+
+{ USB_DEVICE(0x0BB4, 0x00CF) }, /* HTC USB Modem */
+
+Revert the commit which adds the duplicate entry.
+
+This reverts commit 04cab1329336d4577d6638360c905e360934b425.
+
+Originally-by: Ben Collins <ben.collins@canonical.com>
+Signed-off-by: Leann Ogasawara <leann.ogasawara@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/ipaq.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/usb/serial/ipaq.c
++++ b/drivers/usb/serial/ipaq.c
+@@ -534,7 +534,6 @@ static struct usb_device_id ipaq_id_tabl
+ { USB_DEVICE(0x413C, 0x4009) }, /* Dell Axim USB Sync */
+ { USB_DEVICE(0x4505, 0x0010) }, /* Smartphone */
+ { USB_DEVICE(0x5E04, 0xCE00) }, /* SAGEM Wireless Assistant */
+- { USB_DEVICE(0x0BB4, 0x00CF) }, /* HTC smartphone modems */
+ { } /* Terminating entry */
+ };
+
diff --git a/usb/usb-add-a-serial-number-parameter-to-g_file_storage-module.patch b/usb/usb-add-a-serial-number-parameter-to-g_file_storage-module.patch
new file mode 100644
index 00000000000000..5202a997ee66c7
--- /dev/null
+++ b/usb/usb-add-a-serial-number-parameter-to-g_file_storage-module.patch
@@ -0,0 +1,149 @@
+From yann.cantin@laposte.net Wed Jun 16 13:53:56 2010
+From: Yann Cantin <yann.cantin@laposte.net>
+Date: Sat, 5 Jun 2010 23:06:31 +0200
+Subject: USB: Add a serial number parameter to g_file_storage module
+To: dbrownell@users.sourceforge.net
+Cc: linux-usb@vger.kernel.org, Yann Cantin <yann.cantin@laposte.net>
+Message-ID: <1275771991-26392-1-git-send-email-yann.cantin@laposte.net>
+
+
+This patch add a serial number parameter to the g_file_storage
+module. There's validity checks against the string passed to comply
+with the specs.
+
+Signed-off-by: Yann Cantin <yann.cantin@laposte.net>
+Cc: Michał Nazarewicz <m.nazarewicz@samsung.com>
+Cc: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/file_storage.c | 69 +++++++++++++++++++++++++++++++-------
+ 1 file changed, 58 insertions(+), 11 deletions(-)
+
+--- a/drivers/usb/gadget/file_storage.c
++++ b/drivers/usb/gadget/file_storage.c
+@@ -56,7 +56,7 @@
+ * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03),
+ * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by
+ * the optional "protocol" module parameter. In addition, the default
+- * Vendor ID, Product ID, and release number can be overridden.
++ * Vendor ID, Product ID, release number and serial number can be overridden.
+ *
+ * There is support for multiple logical units (LUNs), each of which has
+ * its own backing file. The number of LUNs can be set using the optional
+@@ -106,6 +106,7 @@
+ * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID
+ * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID
+ * release=0xRRRR Override the USB release number (bcdDevice)
++ * serial=HHHH... Override serial number (string of hex chars)
+ * buflen=N Default N=16384, buffer size used (will be
+ * rounded down to a multiple of
+ * PAGE_CACHE_SIZE)
+@@ -270,6 +271,8 @@
+
+ #define DRIVER_DESC "File-backed Storage Gadget"
+ #define DRIVER_NAME "g_file_storage"
++/* DRIVER_VERSION must be at least 6 characters long, as it is used
++ * to generate a fallback serial number. */
+ #define DRIVER_VERSION "20 November 2008"
+
+ static char fsg_string_manufacturer[64];
+@@ -314,6 +317,7 @@ static struct {
+ unsigned short vendor;
+ unsigned short product;
+ unsigned short release;
++ char *serial_parm;
+ unsigned int buflen;
+
+ int transport_type;
+@@ -374,6 +378,9 @@ MODULE_PARM_DESC(product, "USB Product I
+ module_param_named(release, mod_data.release, ushort, S_IRUGO);
+ MODULE_PARM_DESC(release, "USB release number");
+
++module_param_named(serial, mod_data.serial_parm, charp, S_IRUGO);
++MODULE_PARM_DESC(serial, "USB serial number");
++
+ module_param_named(buflen, mod_data.buflen, uint, S_IRUGO);
+ MODULE_PARM_DESC(buflen, "I/O buffer size");
+
+@@ -3197,6 +3204,7 @@ static int __init check_parameters(struc
+ {
+ int prot;
+ int gcnum;
++ int i;
+
+ /* Store the default values */
+ mod_data.transport_type = USB_PR_BULK;
+@@ -3272,6 +3280,55 @@ static int __init check_parameters(struc
+ ERROR(fsg, "invalid buflen\n");
+ return -ETOOSMALL;
+ }
++
++ /* Serial string handling.
++ * On a real device, the serial string would be loaded
++ * from permanent storage. */
++ if (mod_data.serial_parm) {
++ const char *ch;
++ unsigned len = 0;
++
++ /* Sanity check :
++ * The CB[I] specification limits the serial string to
++ * 12 uppercase hexadecimal characters.
++ * BBB need at least 12 uppercase hexadecimal characters,
++ * with a maximum of 126. */
++ for (ch = mod_data.serial_parm; *ch; ++ch) {
++ ++len;
++ if ((*ch < '0' || *ch > '9') &&
++ (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */
++ WARNING(fsg,
++ "Invalid serial string character: %c; "
++ "Failing back to default\n",
++ *ch);
++ goto fill_serial;
++ }
++ }
++ if (len > 126 ||
++ (mod_data.transport_type == USB_PR_BULK && len < 12) ||
++ (mod_data.transport_type != USB_PR_BULK && len > 12)) {
++ WARNING(fsg,
++ "Invalid serial string length; "
++ "Failing back to default\n");
++ goto fill_serial;
++ }
++ fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial_parm;
++ } else {
++fill_serial:
++ /* Serial number not specified or invalid, make our own.
++ * We just encode it from the driver version string,
++ * 12 characters to comply with both CB[I] and BBB spec.
++ * Warning : Two devices running the same kernel will have
++ * the same fallback serial number. */
++ for (i = 0; i < 12; i += 2) {
++ unsigned char c = DRIVER_VERSION[i / 2];
++
++ if (!c)
++ break;
++ sprintf(&fsg_string_serial[i], "%02X", c);
++ }
++ }
++
+ #endif /* CONFIG_USB_FILE_STORAGE_TEST */
+
+ return 0;
+@@ -3447,16 +3504,6 @@ static int __init fsg_bind(struct usb_ga
+ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);
+
+- /* On a real device, serial[] would be loaded from permanent
+- * storage. We just encode it from the driver version string. */
+- for (i = 0; i < sizeof fsg_string_serial - 2; i += 2) {
+- unsigned char c = DRIVER_VERSION[i / 2];
+-
+- if (!c)
+- break;
+- sprintf(&fsg_string_serial[i], "%02X", c);
+- }
+-
+ fsg->thread_task = kthread_create(fsg_main_thread, fsg,
+ "file-storage-gadget");
+ if (IS_ERR(fsg->thread_task)) {
diff --git a/usb/usb-conexant-fixed-spacing-and-brace-coding-style-issues.patch b/usb/usb-conexant-fixed-spacing-and-brace-coding-style-issues.patch
new file mode 100644
index 00000000000000..59a8ad701cd57e
--- /dev/null
+++ b/usb/usb-conexant-fixed-spacing-and-brace-coding-style-issues.patch
@@ -0,0 +1,66 @@
+From nikai@nikai.net Wed Jun 16 13:49:22 2010
+From: Nicolas Kaiser <nikai@nikai.net>
+Date: Wed, 16 Jun 2010 18:56:05 +0200
+Subject: usb: conexant: fixed spacing and brace coding style issues
+To: Simon Arlott <cxacru@fire.lp0.eu>
+Cc: Greg Kroah-Hartman <gregkh@suse.de>, accessrunner-general@lists.sourceforge.net, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org
+Message-ID: <20100616185605.00ce6f31@absol.kitzblitz>
+
+
+Fixed spacing and brace coding style issues.
+
+Signed-off-by: Nicolas Kaiser <nikai@nikai.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/atm/cxacru.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/atm/cxacru.c
++++ b/drivers/usb/atm/cxacru.c
+@@ -564,7 +564,7 @@ static void cxacru_timeout_kill(unsigned
+ }
+
+ static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
+- int* actual_length)
++ int *actual_length)
+ {
+ struct timer_list timer;
+
+@@ -952,7 +952,7 @@ static int cxacru_fw(struct usb_device *
+ put_unaligned(cpu_to_le32(addr), (__le32 *)(buf + offb));
+ offb += 4;
+ addr += l;
+- if(l)
++ if (l)
+ memcpy(buf + offb, data + offd, l);
+ if (l < stride)
+ memset(buf + offb + l, 0, stride - l);
+@@ -967,7 +967,7 @@ static int cxacru_fw(struct usb_device *
+ }
+ offb = 0;
+ }
+- } while(offd < size);
++ } while (offd < size);
+ dbg("sent fw %#x", fw);
+
+ ret = 0;
+@@ -1043,8 +1043,7 @@ static void cxacru_upload_firmware(struc
+ if (instance->modem_type->boot_rom_patch) {
+ val = cpu_to_le32(BR_ADDR);
+ ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4);
+- }
+- else {
++ } else {
+ ret = cxacru_fw(usb_dev, FW_GOTO_MEM, 0x0, 0x0, FW_ADDR, NULL, 0);
+ }
+ if (ret) {
+@@ -1068,7 +1067,7 @@ static void cxacru_upload_firmware(struc
+ }
+
+ static int cxacru_find_firmware(struct cxacru_data *instance,
+- char* phase, const struct firmware **fw_p)
++ char *phase, const struct firmware **fw_p)
+ {
+ struct usbatm_data *usbatm = instance->usbatm;
+ struct device *dev = &usbatm->usb_intf->dev;
diff --git a/usb/usb-ehci-ehci-1.1-addendum-basic-lpm-feature-support.patch b/usb/usb-ehci-ehci-1.1-addendum-basic-lpm-feature-support.patch
new file mode 100644
index 00000000000000..95fac8396679ba
--- /dev/null
+++ b/usb/usb-ehci-ehci-1.1-addendum-basic-lpm-feature-support.patch
@@ -0,0 +1,243 @@
+From alek.du@intel.com Wed Jun 16 13:28:26 2010
+From: Alek Du <alek.du@intel.com>
+Date: Fri, 4 Jun 2010 15:47:55 +0800
+Subject: USB: EHCI: EHCI 1.1 addendum: Basic LPM feature support
+To: greg@kroah.com
+Cc: david-b@pacbell.net, linux-usb@vger.kernel.org, oneukum@suse.de, Alek Du <alek.du@intel.com>, Jacob Pan <jacob.jun.pan@intel.com>
+Message-ID: <1275637676-24880-3-git-send-email-alek.du@intel.com>
+
+
+From: Alek Du <alek.du@intel.com>
+
+With this patch, the LPM capable EHCI host controller can put device
+into L1 sleep state which is a mode that can enter/exit quickly, and
+reduce power consumption.
+
+Signed-off-by: Jacob Pan <jacob.jun.pan@intel.com>
+Signed-off-by: Alek Du <alek.du@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/hub.c | 4 +-
+ drivers/usb/host/ehci-hcd.c | 17 +++++++++
+ drivers/usb/host/ehci-hub.c | 5 ++
+ drivers/usb/host/ehci-lpm.c | 83 ++++++++++++++++++++++++++++++++++++++++++++
+ drivers/usb/host/ehci-pci.c | 21 +++++++++++
+ drivers/usb/host/ehci.h | 2 -
+ include/linux/usb/hcd.h | 4 ++
+ 7 files changed, 134 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -2878,7 +2878,9 @@ hub_port_init (struct usb_hub *hub, stru
+ }
+
+ retval = 0;
+-
++ /* notify HCD that we have a device connected and addressed */
++ if (hcd->driver->update_device)
++ hcd->driver->update_device(hcd, udev);
+ fail:
+ if (retval) {
+ hub_port_disable(hub, port1, 0);
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -100,6 +100,11 @@ static int ignore_oc = 0;
+ module_param (ignore_oc, bool, S_IRUGO);
+ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
+
++/* for link power management(LPM) feature */
++static unsigned int hird;
++module_param(hird, int, S_IRUGO);
++MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us\n");
++
+ #define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
+
+ /*-------------------------------------------------------------------------*/
+@@ -304,6 +309,7 @@ static void end_unlink_async(struct ehci
+ static void ehci_work(struct ehci_hcd *ehci);
+
+ #include "ehci-hub.c"
++#include "ehci-lpm.c"
+ #include "ehci-mem.c"
+ #include "ehci-q.c"
+ #include "ehci-sched.c"
+@@ -603,6 +609,17 @@ static int ehci_init(struct usb_hcd *hcd
+ default: BUG();
+ }
+ }
++ if (HCC_LPM(hcc_params)) {
++ /* support link power management EHCI 1.1 addendum */
++ ehci_dbg(ehci, "support lpm\n");
++ ehci->has_lpm = 1;
++ if (hird > 0xf) {
++ ehci_dbg(ehci, "hird %d invalid, use default 0",
++ hird);
++ hird = 0;
++ }
++ temp |= hird << 24;
++ }
+ ehci->command = temp;
+
+ /* Accept arbitrarily long scatter-gather lists */
+--- a/drivers/usb/host/ehci-hub.c
++++ b/drivers/usb/host/ehci-hub.c
+@@ -790,6 +790,11 @@ static int ehci_hub_control (
+ status_reg);
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
++ if (ehci->has_lpm) {
++ /* clear PORTSC bits on disconnect */
++ temp &= ~PORT_LPM;
++ temp &= ~PORT_DEV_ADDR;
++ }
+ ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
+ status_reg);
+ break;
+--- /dev/null
++++ b/drivers/usb/host/ehci-lpm.c
+@@ -0,0 +1,83 @@
++/* ehci-lpm.c EHCI HCD LPM support code
++ * Copyright (c) 2008 - 2010, Intel Corporation.
++ * Author: Jacob Pan <jacob.jun.pan@intel.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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++*/
++
++/* this file is part of ehci-hcd.c */
++static int ehci_lpm_set_da(struct ehci_hcd *ehci, int dev_addr, int port_num)
++{
++ u32 __iomem portsc;
++
++ ehci_dbg(ehci, "set dev address %d for port %d\n", dev_addr, port_num);
++ if (port_num > HCS_N_PORTS(ehci->hcs_params)) {
++ ehci_dbg(ehci, "invalid port number %d\n", port_num);
++ return -ENODEV;
++ }
++ portsc = ehci_readl(ehci, &ehci->regs->port_status[port_num-1]);
++ portsc &= ~PORT_DEV_ADDR;
++ portsc |= dev_addr<<25;
++ ehci_writel(ehci, portsc, &ehci->regs->port_status[port_num-1]);
++ return 0;
++}
++
++/*
++ * this function is used to check if the device support LPM
++ * if yes, mark the PORTSC register with PORT_LPM bit
++ */
++static int ehci_lpm_check(struct ehci_hcd *ehci, int port)
++{
++ u32 __iomem *portsc ;
++ u32 val32;
++ int retval;
++
++ portsc = &ehci->regs->port_status[port-1];
++ val32 = ehci_readl(ehci, portsc);
++ if (!(val32 & PORT_DEV_ADDR)) {
++ ehci_dbg(ehci, "LPM: no device attached\n");
++ return -ENODEV;
++ }
++ val32 |= PORT_LPM;
++ ehci_writel(ehci, val32, portsc);
++ msleep(5);
++ val32 |= PORT_SUSPEND;
++ ehci_dbg(ehci, "Sending LPM 0x%08x to port %d\n", val32, port);
++ ehci_writel(ehci, val32, portsc);
++ /* wait for ACK */
++ msleep(10);
++ retval = handshake(ehci, &ehci->regs->port_status[port-1], PORT_SSTS,
++ PORTSC_SUSPEND_STS_ACK, 125);
++ dbg_port(ehci, "LPM", port, val32);
++ if (retval != -ETIMEDOUT) {
++ ehci_dbg(ehci, "LPM: device ACK for LPM\n");
++ val32 |= PORT_LPM;
++ /*
++ * now device should be in L1 sleep, let's wake up the device
++ * so that we can complete enumeration.
++ */
++ ehci_writel(ehci, val32, portsc);
++ msleep(10);
++ val32 |= PORT_RESUME;
++ ehci_writel(ehci, val32, portsc);
++ } else {
++ ehci_dbg(ehci, "LPM: device does not ACK, disable LPM %d\n",
++ retval);
++ val32 &= ~PORT_LPM;
++ retval = -ETIMEDOUT;
++ ehci_writel(ehci, val32, portsc);
++ }
++
++ return retval;
++}
+--- a/drivers/usb/host/ehci-pci.c
++++ b/drivers/usb/host/ehci-pci.c
+@@ -361,6 +361,22 @@ static int ehci_pci_resume(struct usb_hc
+ }
+ #endif
+
++static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
++{
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++ int rc = 0;
++
++ if (!udev->parent) /* udev is root hub itself, impossible */
++ rc = -1;
++ /* we only support lpm device connected to root hub yet */
++ if (ehci->has_lpm && !udev->parent->parent) {
++ rc = ehci_lpm_set_da(ehci, udev->devnum, udev->portnum);
++ if (!rc)
++ rc = ehci_lpm_check(ehci, udev->portnum);
++ }
++ return rc;
++}
++
+ static const struct hc_driver ehci_pci_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "EHCI Host Controller",
+@@ -407,6 +423,11 @@ static const struct hc_driver ehci_pci_h
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
++ /*
++ * call back when device connected and addressed
++ */
++ .update_device = ehci_update_device,
++
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+ };
+
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -140,7 +140,7 @@ struct ehci_hcd { /* one per controlle
+ #define OHCI_HCCTRL_LEN 0x4
+ __hc32 *ohci_hcctrl_reg;
+ unsigned has_hostpc:1;
+-
++ unsigned has_lpm:1; /* support link power management */
+ u8 sbrn; /* packed release number */
+
+ /* irq statistics */
+--- a/include/linux/usb/hcd.h
++++ b/include/linux/usb/hcd.h
+@@ -300,6 +300,10 @@ struct hc_driver {
+ int (*update_hub_device)(struct usb_hcd *, struct usb_device *hdev,
+ struct usb_tt *tt, gfp_t mem_flags);
+ int (*reset_device)(struct usb_hcd *, struct usb_device *);
++ /* Notifies the HCD after a device is connected and its
++ * address is set
++ */
++ int (*update_device)(struct usb_hcd *, struct usb_device *);
+ };
+
+ extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
diff --git a/usb/usb-ehci-ehci-1.1-addendum-enable-per-port-change-detect-bits.patch b/usb/usb-ehci-ehci-1.1-addendum-enable-per-port-change-detect-bits.patch
new file mode 100644
index 00000000000000..2aa59fb010338c
--- /dev/null
+++ b/usb/usb-ehci-ehci-1.1-addendum-enable-per-port-change-detect-bits.patch
@@ -0,0 +1,104 @@
+From alek.du@intel.com Wed Jun 16 13:29:07 2010
+From: Alek Du <alek.du@intel.com>
+Date: Fri, 4 Jun 2010 15:47:56 +0800
+Subject: USB: EHCI: EHCI 1.1 addendum: Enable Per-port change detect bits
+To: greg@kroah.com
+Cc: david-b@pacbell.net, linux-usb@vger.kernel.org, oneukum@suse.de, Alek Du <alek.du@intel.com>
+Message-ID: <1275637676-24880-4-git-send-email-alek.du@intel.com>
+
+
+From: Alek Du <alek.du@intel.com>
+
+This patch will enable Per-port event feature defined in EHCI 1.1
+addendum. This feature addresses an issue where HCD is currently
+required to read and parse PORTSC for all enabled root hub ports. With
+this patch, the overhead will be reduced.
+
+Signed-off-by: Alek Du <alek.du@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ehci-hcd.c | 19 +++++++++++++++++--
+ drivers/usb/host/ehci-hub.c | 9 +++++++++
+ drivers/usb/host/ehci.h | 1 +
+ 3 files changed, 27 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -583,6 +583,11 @@ static int ehci_init(struct usb_hcd *hcd
+ if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
+ log2_irq_thresh = 0;
+ temp = 1 << (16 + log2_irq_thresh);
++ if (HCC_PER_PORT_CHANGE_EVENT(hcc_params)) {
++ ehci->has_ppcd = 1;
++ ehci_dbg(ehci, "enable per-port change event\n");
++ temp |= CMD_PPCEE;
++ }
+ if (HCC_CANPARK(hcc_params)) {
+ /* HW default park == 3, on hardware that supports it (like
+ * NVidia and ALI silicon), maximizes throughput on the async
+@@ -781,6 +786,7 @@ static irqreturn_t ehci_irq (struct usb_
+ /* remote wakeup [4.3.1] */
+ if (status & STS_PCD) {
+ unsigned i = HCS_N_PORTS (ehci->hcs_params);
++ u32 ppcd = 0;
+
+ /* kick root hub later */
+ pcd_status = status;
+@@ -789,9 +795,18 @@ static irqreturn_t ehci_irq (struct usb_
+ if (!(cmd & CMD_RUN))
+ usb_hcd_resume_root_hub(hcd);
+
++ /* get per-port change detect bits */
++ if (ehci->has_ppcd)
++ ppcd = status >> 16;
++
+ while (i--) {
+- int pstatus = ehci_readl(ehci,
+- &ehci->regs->port_status [i]);
++ int pstatus;
++
++ /* leverage per-port change bits feature */
++ if (ehci->has_ppcd && !(ppcd & (1 << i)))
++ continue;
++ pstatus = ehci_readl(ehci,
++ &ehci->regs->port_status[i]);
+
+ if (pstatus & PORT_OWNER)
+ continue;
+--- a/drivers/usb/host/ehci-hub.c
++++ b/drivers/usb/host/ehci-hub.c
+@@ -603,6 +603,7 @@ ehci_hub_status_data (struct usb_hcd *hc
+ u32 mask;
+ int ports, i, retval = 1;
+ unsigned long flags;
++ u32 ppcd = 0;
+
+ /* if !USB_SUSPEND, root hub timers won't get shut down ... */
+ if (!HC_IS_RUNNING(hcd->state))
+@@ -632,7 +633,15 @@ ehci_hub_status_data (struct usb_hcd *hc
+
+ /* port N changes (bit N)? */
+ spin_lock_irqsave (&ehci->lock, flags);
++
++ /* get per-port change detect bits */
++ if (ehci->has_ppcd)
++ ppcd = ehci_readl(ehci, &ehci->regs->status) >> 16;
++
+ for (i = 0; i < ports; i++) {
++ /* leverage per-port change bits feature */
++ if (ehci->has_ppcd && !(ppcd & (1 << i)))
++ continue;
+ temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
+
+ /*
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -141,6 +141,7 @@ struct ehci_hcd { /* one per controlle
+ __hc32 *ohci_hcctrl_reg;
+ unsigned has_hostpc:1;
+ unsigned has_lpm:1; /* support link power management */
++ unsigned has_ppcd:1; /* support per-port change bits */
+ u8 sbrn; /* packed release number */
+
+ /* irq statistics */
diff --git a/usb/usb-ehci-ehci-1.1-addendum-preparation.patch b/usb/usb-ehci-ehci-1.1-addendum-preparation.patch
new file mode 100644
index 00000000000000..21ad12d6232f20
--- /dev/null
+++ b/usb/usb-ehci-ehci-1.1-addendum-preparation.patch
@@ -0,0 +1,323 @@
+From alek.du@intel.com Wed Jun 16 13:27:54 2010
+From: Alek Du <alek.du@intel.com>
+Date: Fri, 4 Jun 2010 15:47:54 +0800
+Subject: USB: EHCI: EHCI 1.1 addendum: preparation
+To: greg@kroah.com
+Cc: david-b@pacbell.net, linux-usb@vger.kernel.org, oneukum@suse.de, Alek Du <alek.du@intel.com>, Jacob Pan <jacob.jun.pan@intel.com>
+Message-ID: <1275637676-24880-2-git-send-email-alek.du@intel.com>
+
+
+From: Alek Du <alek.du@intel.com>
+
+EHCI 1.1 addendum introduced several energy efficiency extensions for
+EHCI USB host controllers:
+1. LPM (link power management)
+2. Per-port change
+3. Shorter periodic frame list
+4. Hardware prefetching
+
+This patch is intended to define the HW bits and debug interface for
+EHCI 1.1 addendum. The LPM and Per-port change patches will be sent out
+after this patch.
+
+Signed-off-by: Jacob Pan <jacob.jun.pan@intel.com>
+Signed-off-by: Alek Du <alek.du@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ehci-dbg.c | 144 ++++++++++++++++++++++++++++++++++++++++---
+ drivers/usb/host/ehci.h | 1
+ include/linux/usb/ehci_def.h | 23 ++++++
+ 3 files changed, 161 insertions(+), 7 deletions(-)
+
+--- a/drivers/usb/host/ehci-dbg.c
++++ b/drivers/usb/host/ehci-dbg.c
+@@ -98,13 +98,18 @@ static void dbg_hcc_params (struct ehci_
+ HCC_64BIT_ADDR(params) ? " 64 bit addr" : "");
+ } else {
+ ehci_dbg (ehci,
+- "%s hcc_params %04x thresh %d uframes %s%s%s\n",
++ "%s hcc_params %04x thresh %d uframes %s%s%s%s%s%s%s\n",
+ label,
+ params,
+ HCC_ISOC_THRES(params),
+ HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
+ HCC_CANPARK(params) ? " park" : "",
+- HCC_64BIT_ADDR(params) ? " 64 bit addr" : "");
++ HCC_64BIT_ADDR(params) ? " 64 bit addr" : "",
++ HCC_LPM(params) ? " LPM" : "",
++ HCC_PER_PORT_CHANGE_EVENT(params) ? " ppce" : "",
++ HCC_HW_PREFETCH(params) ? " hw prefetch" : "",
++ HCC_32FRAME_PERIODIC_LIST(params) ?
++ " 32 peridic list" : "");
+ }
+ }
+ #else
+@@ -191,8 +196,9 @@ static int __maybe_unused
+ dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
+ {
+ return scnprintf (buf, len,
+- "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
++ "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s%s",
+ label, label [0] ? " " : "", status,
++ (status & STS_PPCE_MASK) ? " PPCE" : "",
+ (status & STS_ASS) ? " Async" : "",
+ (status & STS_PSS) ? " Periodic" : "",
+ (status & STS_RECL) ? " Recl" : "",
+@@ -210,8 +216,9 @@ static int __maybe_unused
+ dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
+ {
+ return scnprintf (buf, len,
+- "%s%sintrenable %02x%s%s%s%s%s%s",
++ "%s%sintrenable %02x%s%s%s%s%s%s%s",
+ label, label [0] ? " " : "", enable,
++ (enable & STS_PPCE_MASK) ? " PPCE" : "",
+ (enable & STS_IAA) ? " IAA" : "",
+ (enable & STS_FATAL) ? " FATAL" : "",
+ (enable & STS_FLR) ? " FLR" : "",
+@@ -228,9 +235,15 @@ static int
+ dbg_command_buf (char *buf, unsigned len, const char *label, u32 command)
+ {
+ return scnprintf (buf, len,
+- "%s%scommand %06x %s=%d ithresh=%d%s%s%s%s period=%s%s %s",
++ "%s%scommand %07x %s%s%s%s%s%s=%d ithresh=%d%s%s%s%s "
++ "period=%s%s %s",
+ label, label [0] ? " " : "", command,
+- (command & CMD_PARK) ? "park" : "(park)",
++ (command & CMD_HIRD) ? " HIRD" : "",
++ (command & CMD_PPCEE) ? " PPCEE" : "",
++ (command & CMD_FSP) ? " FSP" : "",
++ (command & CMD_ASPE) ? " ASPE" : "",
++ (command & CMD_PSPE) ? " PSPE" : "",
++ (command & CMD_PARK) ? " park" : "(park)",
+ CMD_PARK_CNT (command),
+ (command >> 16) & 0x3f,
+ (command & CMD_LRESET) ? " LReset" : "",
+@@ -257,11 +270,22 @@ dbg_port_buf (char *buf, unsigned len, c
+ }
+
+ return scnprintf (buf, len,
+- "%s%sport %d status %06x%s%s sig=%s%s%s%s%s%s%s%s%s%s",
++ "%s%sport:%d status %06x %d %s%s%s%s%s%s "
++ "sig=%s%s%s%s%s%s%s%s%s%s%s",
+ label, label [0] ? " " : "", port, status,
++ status>>25,/*device address */
++ (status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_ACK ?
++ " ACK" : "",
++ (status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_NYET ?
++ " NYET" : "",
++ (status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_STALL ?
++ " STALL" : "",
++ (status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_ERR ?
++ " ERR" : "",
+ (status & PORT_POWER) ? " POWER" : "",
+ (status & PORT_OWNER) ? " OWNER" : "",
+ sig,
++ (status & PORT_LPM) ? " LPM" : "",
+ (status & PORT_RESET) ? " RESET" : "",
+ (status & PORT_SUSPEND) ? " SUSPEND" : "",
+ (status & PORT_RESUME) ? " RESUME" : "",
+@@ -330,6 +354,13 @@ static int debug_async_open(struct inode
+ static int debug_periodic_open(struct inode *, struct file *);
+ static int debug_registers_open(struct inode *, struct file *);
+ static int debug_async_open(struct inode *, struct file *);
++static int debug_lpm_open(struct inode *, struct file *);
++static ssize_t debug_lpm_read(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos);
++static ssize_t debug_lpm_write(struct file *file, const char __user *buffer,
++ size_t count, loff_t *ppos);
++static int debug_lpm_close(struct inode *inode, struct file *file);
++
+ static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
+ static int debug_close(struct inode *, struct file *);
+
+@@ -351,6 +382,13 @@ static const struct file_operations debu
+ .read = debug_output,
+ .release = debug_close,
+ };
++static const struct file_operations debug_lpm_fops = {
++ .owner = THIS_MODULE,
++ .open = debug_lpm_open,
++ .read = debug_lpm_read,
++ .write = debug_lpm_write,
++ .release = debug_lpm_close,
++};
+
+ static struct dentry *ehci_debug_root;
+
+@@ -917,6 +955,94 @@ static int debug_registers_open(struct i
+ return file->private_data ? 0 : -ENOMEM;
+ }
+
++static int debug_lpm_open(struct inode *inode, struct file *file)
++{
++ file->private_data = inode->i_private;
++ return 0;
++}
++
++static int debug_lpm_close(struct inode *inode, struct file *file)
++{
++ return 0;
++}
++
++static ssize_t debug_lpm_read(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ /* TODO: show lpm stats */
++ return 0;
++}
++
++static ssize_t debug_lpm_write(struct file *file, const char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct usb_hcd *hcd;
++ struct ehci_hcd *ehci;
++ char buf[50];
++ size_t len;
++ u32 temp;
++ unsigned long port;
++ u32 __iomem *portsc ;
++ u32 params;
++
++ hcd = bus_to_hcd(file->private_data);
++ ehci = hcd_to_ehci(hcd);
++
++ len = min(count, sizeof(buf) - 1);
++ if (copy_from_user(buf, user_buf, len))
++ return -EFAULT;
++ buf[len] = '\0';
++ if (len > 0 && buf[len - 1] == '\n')
++ buf[len - 1] = '\0';
++
++ if (strncmp(buf, "enable", 5) == 0) {
++ if (strict_strtoul(buf + 7, 10, &port))
++ return -EINVAL;
++ params = ehci_readl(ehci, &ehci->caps->hcs_params);
++ if (port > HCS_N_PORTS(params)) {
++ ehci_dbg(ehci, "ERR: LPM on bad port %lu\n", port);
++ return -ENODEV;
++ }
++ portsc = &ehci->regs->port_status[port-1];
++ temp = ehci_readl(ehci, portsc);
++ if (!(temp & PORT_DEV_ADDR)) {
++ ehci_dbg(ehci, "LPM: no device attached\n");
++ return -ENODEV;
++ }
++ temp |= PORT_LPM;
++ ehci_writel(ehci, temp, portsc);
++ printk(KERN_INFO "force enable LPM for port %lu\n", port);
++ } else if (strncmp(buf, "hird=", 5) == 0) {
++ unsigned long hird;
++ if (strict_strtoul(buf + 5, 16, &hird))
++ return -EINVAL;
++ printk(KERN_INFO "setting hird %s %lu\n", buf + 6, hird);
++ temp = ehci_readl(ehci, &ehci->regs->command);
++ temp &= ~CMD_HIRD;
++ temp |= hird << 24;
++ ehci_writel(ehci, temp, &ehci->regs->command);
++ } else if (strncmp(buf, "disable", 7) == 0) {
++ if (strict_strtoul(buf + 8, 10, &port))
++ return -EINVAL;
++ params = ehci_readl(ehci, &ehci->caps->hcs_params);
++ if (port > HCS_N_PORTS(params)) {
++ ehci_dbg(ehci, "ERR: LPM off bad port %lu\n", port);
++ return -ENODEV;
++ }
++ portsc = &ehci->regs->port_status[port-1];
++ temp = ehci_readl(ehci, portsc);
++ if (!(temp & PORT_DEV_ADDR)) {
++ ehci_dbg(ehci, "ERR: no device attached\n");
++ return -ENODEV;
++ }
++ temp &= ~PORT_LPM;
++ ehci_writel(ehci, temp, portsc);
++ printk(KERN_INFO "disabled LPM for port %lu\n", port);
++ } else
++ return -EOPNOTSUPP;
++ return count;
++}
++
+ static inline void create_debug_files (struct ehci_hcd *ehci)
+ {
+ struct usb_bus *bus = &ehci_to_hcd(ehci)->self;
+@@ -940,6 +1066,10 @@ static inline void create_debug_files (s
+ ehci->debug_registers = debugfs_create_file("registers", S_IRUGO,
+ ehci->debug_dir, bus,
+ &debug_registers_fops);
++
++ ehci->debug_registers = debugfs_create_file("lpm", S_IRUGO|S_IWUGO,
++ ehci->debug_dir, bus,
++ &debug_lpm_fops);
+ if (!ehci->debug_registers)
+ goto registers_error;
+ return;
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -157,6 +157,7 @@ struct ehci_hcd { /* one per controlle
+ struct dentry *debug_async;
+ struct dentry *debug_periodic;
+ struct dentry *debug_registers;
++ struct dentry *debug_lpm;
+ #endif
+ };
+
+--- a/include/linux/usb/ehci_def.h
++++ b/include/linux/usb/ehci_def.h
+@@ -39,6 +39,12 @@ struct ehci_caps {
+ #define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
+
+ u32 hcc_params; /* HCCPARAMS - offset 0x8 */
++/* EHCI 1.1 addendum */
++#define HCC_32FRAME_PERIODIC_LIST(p) ((p)&(1 << 19))
++#define HCC_PER_PORT_CHANGE_EVENT(p) ((p)&(1 << 18))
++#define HCC_LPM(p) ((p)&(1 << 17))
++#define HCC_HW_PREFETCH(p) ((p)&(1 << 16))
++
+ #define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */
+ #define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
+ #define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
+@@ -54,6 +60,13 @@ struct ehci_regs {
+
+ /* USBCMD: offset 0x00 */
+ u32 command;
++
++/* EHCI 1.1 addendum */
++#define CMD_HIRD (0xf<<24) /* host initiated resume duration */
++#define CMD_PPCEE (1<<15) /* per port change event enable */
++#define CMD_FSP (1<<14) /* fully synchronized prefetch */
++#define CMD_ASPE (1<<13) /* async schedule prefetch enable */
++#define CMD_PSPE (1<<12) /* periodic schedule prefetch enable */
+ /* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
+ #define CMD_PARK (1<<11) /* enable "park" on async qh */
+ #define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */
+@@ -67,6 +80,7 @@ struct ehci_regs {
+
+ /* USBSTS: offset 0x04 */
+ u32 status;
++#define STS_PPCE_MASK (0xff<<16) /* Per-Port change event 1-16 */
+ #define STS_ASS (1<<15) /* Async Schedule Status */
+ #define STS_PSS (1<<14) /* Periodic Schedule Status */
+ #define STS_RECL (1<<13) /* Reclamation */
+@@ -100,6 +114,14 @@ struct ehci_regs {
+
+ /* PORTSC: offset 0x44 */
+ u32 port_status[0]; /* up to N_PORTS */
++/* EHCI 1.1 addendum */
++#define PORTSC_SUSPEND_STS_ACK 0
++#define PORTSC_SUSPEND_STS_NYET 1
++#define PORTSC_SUSPEND_STS_STALL 2
++#define PORTSC_SUSPEND_STS_ERR 3
++
++#define PORT_DEV_ADDR (0x7f<<25) /* device address */
++#define PORT_SSTS (0x3<<23) /* suspend status */
+ /* 31:23 reserved */
+ #define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */
+ #define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */
+@@ -115,6 +137,7 @@ struct ehci_regs {
+ #define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */
+ /* 11:10 for detecting lowspeed devices (reset vs release ownership) */
+ /* 9 reserved */
++#define PORT_LPM (1<<9) /* LPM transaction */
+ #define PORT_RESET (1<<8) /* reset port */
+ #define PORT_SUSPEND (1<<7) /* suspend port */
+ #define PORT_RESUME (1<<6) /* resume it */
diff --git a/usb/usb-gadget-langwell_udc.c-printk-needs-a-unsigned-long-long-cast-for-a-dma_t.patch b/usb/usb-gadget-langwell_udc.c-printk-needs-a-unsigned-long-long-cast-for-a-dma_t.patch
new file mode 100644
index 00000000000000..154221af9463b0
--- /dev/null
+++ b/usb/usb-gadget-langwell_udc.c-printk-needs-a-unsigned-long-long-cast-for-a-dma_t.patch
@@ -0,0 +1,31 @@
+From joe@perches.com Wed Jun 16 13:30:08 2010
+From: Joe Perches <joe@perches.com>
+Date: Thu, 10 Jun 2010 19:20:43 -0700
+Subject: USB: gadget: langwell_udc.c: printk needs a (unsigned long long) cast for a dma_t
+To: Xiaochen Shen <xiaochen.shen@intel.com>
+Cc: David Brownell <dbrownell@users.sourceforge.net>, Greg Kroah-Hartman <gregkh@suse.de>, linux-usb <linux-usb@vger.kernel.org>, LKML <linux-kernel@vger.kernel.org>
+Message-ID: <1276222843.1556.438.camel@Joe-Laptop.home>
+
+
+Signed-off-by: Joe Perches <joe@perches.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/langwell_udc.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/gadget/langwell_udc.c
++++ b/drivers/usb/gadget/langwell_udc.c
+@@ -842,9 +842,9 @@ static int langwell_ep_queue(struct usb_
+ VDBG(dev, "req->mapped = 0\n");
+ }
+
+- DBG(dev, "%s queue req %p, len %u, buf %p, dma 0x%08x\n",
+- _ep->name,
+- _req, _req->length, _req->buf, _req->dma);
++ DBG(dev, "%s queue req %p, len %u, buf %p, dma 0x%08llx\n",
++ _ep->name,
++ _req, _req->length, _req->buf, (unsigned long long)_req->dma);
+
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
diff --git a/usb/usb-option-remove-duplicate-amoi_vendor_id.patch b/usb/usb-option-remove-duplicate-amoi_vendor_id.patch
new file mode 100644
index 00000000000000..2d86097f361c0a
--- /dev/null
+++ b/usb/usb-option-remove-duplicate-amoi_vendor_id.patch
@@ -0,0 +1,41 @@
+From leann.ogasawara@canonical.com Wed Jun 16 13:29:36 2010
+From: Leann Ogasawara <leann.ogasawara@canonical.com>
+Date: Thu, 10 Jun 2010 14:51:51 -0700
+Subject: USB: option: Remove duplicate AMOI_VENDOR_ID
+To: smurf@smurf.noris.de
+Cc: linux-usb@vger.kernel.org
+Message-ID: <1276206711.1221.3631.camel@emiko>
+
+
+AMOI_VENDOR_ID is defined twice. Remove the duplicate entry and move
+the AMOI_PRODUCT_9508 definition to be grouped with the other AMOI
+product definitions.
+
+Originally-by: Ben Collins <ben.collins@ubuntu.com>
+Signed-off-by: Leann Ogasawara <leann.ogasawara@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/option.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -206,6 +206,7 @@ static void option_instat_callback(struc
+ #define AMOI_PRODUCT_H01 0x0800
+ #define AMOI_PRODUCT_H01A 0x7002
+ #define AMOI_PRODUCT_H02 0x0802
++#define AMOI_PRODUCT_9508 0x0800
+
+ #define DELL_VENDOR_ID 0x413C
+
+@@ -263,9 +264,6 @@ static void option_instat_callback(struc
+ #define BANDRICH_PRODUCT_1011 0x1011
+ #define BANDRICH_PRODUCT_1012 0x1012
+
+-#define AMOI_VENDOR_ID 0x1614
+-#define AMOI_PRODUCT_9508 0x0800
+-
+ #define QUALCOMM_VENDOR_ID 0x05C6
+
+ #define CMOTECH_VENDOR_ID 0x16d8
diff --git a/usb/usb-throw-away-custom-hex-digit-methods.patch b/usb/usb-throw-away-custom-hex-digit-methods.patch
new file mode 100644
index 00000000000000..8738f9fba0667e
--- /dev/null
+++ b/usb/usb-throw-away-custom-hex-digit-methods.patch
@@ -0,0 +1,81 @@
+From andy.shevchenko@gmail.com Wed Jun 16 13:22:24 2010
+From: Andy Shevchenko <andy.shevchenko@gmail.com>
+Date: Tue, 15 Jun 2010 17:04:44 +0300
+Subject: usb: throw away custom hex digit methods
+To: linux-kernel@vger.kernel.org
+Cc: Andy Shevchenko <ext-andriy.shevchenko@nokia.com>, Greg Kroah-Hartman <gregkh@suse.de>, David Brownell <dbrownell@users.sourceforge.net>, linux-usb@vger.kernel.org
+Message-ID: <1276610684-26335-1-git-send-email-andy.shevchenko@gmail.com>
+
+
+From: Andy Shevchenko <ext-andriy.shevchenko@nokia.com>
+
+Recent kernel has common method to convert hex digit to its value.
+
+Signed-off-by: Andy Shevchenko <ext-andriy.shevchenko@nokia.com>
+Cc: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/atm/ueagle-atm.c | 5 +++--
+ drivers/usb/gadget/u_ether.c | 15 ++-------------
+ 2 files changed, 5 insertions(+), 15 deletions(-)
+
+--- a/drivers/usb/atm/ueagle-atm.c
++++ b/drivers/usb/atm/ueagle-atm.c
+@@ -67,6 +67,7 @@
+ #include <linux/mutex.h>
+ #include <linux/freezer.h>
+ #include <linux/slab.h>
++#include <linux/kernel.h>
+
+ #include <asm/unaligned.h>
+
+@@ -2429,7 +2430,6 @@ UEA_ATTR(firmid, 0);
+
+ /* Retrieve the device End System Identifier (MAC) */
+
+-#define htoi(x) (isdigit(x) ? x-'0' : toupper(x)-'A'+10)
+ static int uea_getesi(struct uea_softc *sc, u_char * esi)
+ {
+ unsigned char mac_str[2 * ETH_ALEN + 1];
+@@ -2440,7 +2440,8 @@ static int uea_getesi(struct uea_softc *
+ return 1;
+
+ for (i = 0; i < ETH_ALEN; i++)
+- esi[i] = htoi(mac_str[2 * i]) * 16 + htoi(mac_str[2 * i + 1]);
++ esi[i] = hex_to_bin(mac_str[2 * i]) * 16 +
++ hex_to_bin(mac_str[2 * i + 1]);
+
+ return 0;
+ }
+--- a/drivers/usb/gadget/u_ether.c
++++ b/drivers/usb/gadget/u_ether.c
+@@ -704,17 +704,6 @@ static char *host_addr;
+ module_param(host_addr, charp, S_IRUGO);
+ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
+
+-
+-static u8 __init nibble(unsigned char c)
+-{
+- if (isdigit(c))
+- return c - '0';
+- c = toupper(c);
+- if (isxdigit(c))
+- return 10 + c - 'A';
+- return 0;
+-}
+-
+ static int get_ether_addr(const char *str, u8 *dev_addr)
+ {
+ if (str) {
+@@ -725,8 +714,8 @@ static int get_ether_addr(const char *st
+
+ if ((*str == '.') || (*str == ':'))
+ str++;
+- num = nibble(*str++) << 4;
+- num |= (nibble(*str++));
++ num = hex_to_bin(*str++) << 4;
++ num |= hex_to_bin(*str++);
+ dev_addr [i] = num;
+ }
+ if (is_valid_ether_addr(dev_addr))
diff --git a/usb/usb-uvc-move-constants-and-structures-definitions-to-linux-usb-video.h.patch b/usb/usb-uvc-move-constants-and-structures-definitions-to-linux-usb-video.h.patch
new file mode 100644
index 00000000000000..59c6f4834cb351
--- /dev/null
+++ b/usb/usb-uvc-move-constants-and-structures-definitions-to-linux-usb-video.h.patch
@@ -0,0 +1,1044 @@
+From laurent.pinchart@ideasonboard.com Wed Jun 16 13:25:39 2010
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Mon, 7 Jun 2010 13:09:47 +0200
+Subject: USB: uvc: Move constants and structures definitions to linux/usb/video.h
+To: linux-usb@vger.kernel.org
+Message-ID: <1275908987-5774-1-git-send-email-laurent.pinchart@ideasonboard.com>
+
+
+The UVC host and gadget drivers both define constants and structures in
+private header files. Move all those definitions to linux/usb/video.h
+where they can be shared by the two drivers (and be available for
+userspace applications).
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/video/uvc/uvcvideo.h | 19 -
+ drivers/usb/gadget/f_uvc.c | 16 -
+ drivers/usb/gadget/f_uvc.h | 352 --------------------------------
+ drivers/usb/gadget/uvc.h | 36 ---
+ drivers/usb/gadget/webcam.c | 24 +-
+ include/linux/usb/video.h | 397 +++++++++++++++++++++++++++++++++++++
+ 6 files changed, 418 insertions(+), 426 deletions(-)
+
+--- a/drivers/media/video/uvc/uvcvideo.h
++++ b/drivers/media/video/uvc/uvcvideo.h
+@@ -179,25 +179,6 @@ struct uvc_device;
+ /* TODO: Put the most frequently accessed fields at the beginning of
+ * structures to maximize cache efficiency.
+ */
+-struct uvc_streaming_control {
+- __u16 bmHint;
+- __u8 bFormatIndex;
+- __u8 bFrameIndex;
+- __u32 dwFrameInterval;
+- __u16 wKeyFrameRate;
+- __u16 wPFrameRate;
+- __u16 wCompQuality;
+- __u16 wCompWindowSize;
+- __u16 wDelay;
+- __u32 dwMaxVideoFrameSize;
+- __u32 dwMaxPayloadTransferSize;
+- __u32 dwClockFrequency;
+- __u8 bmFramingInfo;
+- __u8 bPreferedVersion;
+- __u8 bMinVersion;
+- __u8 bMaxVersion;
+-};
+-
+ struct uvc_menu_info {
+ __u32 value;
+ __u8 name[32];
+--- a/drivers/usb/gadget/f_uvc.c
++++ b/drivers/usb/gadget/f_uvc.c
+@@ -61,12 +61,12 @@ static struct usb_gadget_strings *uvc_fu
+ #define UVC_INTF_VIDEO_STREAMING 1
+
+ static struct usb_interface_assoc_descriptor uvc_iad __initdata = {
+- .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
++ .bLength = sizeof(uvc_iad),
+ .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
+ .bFirstInterface = 0,
+ .bInterfaceCount = 2,
+ .bFunctionClass = USB_CLASS_VIDEO,
+- .bFunctionSubClass = 0x03,
++ .bFunctionSubClass = UVC_SC_VIDEO_INTERFACE_COLLECTION,
+ .bFunctionProtocol = 0x00,
+ .iFunction = 0,
+ };
+@@ -78,7 +78,7 @@ static struct usb_interface_descriptor u
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+- .bInterfaceSubClass = 0x01,
++ .bInterfaceSubClass = UVC_SC_VIDEOCONTROL,
+ .bInterfaceProtocol = 0x00,
+ .iInterface = 0,
+ };
+@@ -106,7 +106,7 @@ static struct usb_interface_descriptor u
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+- .bInterfaceSubClass = 0x02,
++ .bInterfaceSubClass = UVC_SC_VIDEOSTREAMING,
+ .bInterfaceProtocol = 0x00,
+ .iInterface = 0,
+ };
+@@ -118,7 +118,7 @@ static struct usb_interface_descriptor u
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+- .bInterfaceSubClass = 0x02,
++ .bInterfaceSubClass = UVC_SC_VIDEOSTREAMING,
+ .bInterfaceProtocol = 0x00,
+ .iInterface = 0,
+ };
+@@ -603,15 +603,15 @@ uvc_bind_config(struct usb_configuration
+
+ /* Validate the descriptors. */
+ if (control == NULL || control[0] == NULL ||
+- control[0]->bDescriptorSubType != UVC_DT_HEADER)
++ control[0]->bDescriptorSubType != UVC_VC_HEADER)
+ goto error;
+
+ if (fs_streaming == NULL || fs_streaming[0] == NULL ||
+- fs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER)
++ fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
+ goto error;
+
+ if (hs_streaming == NULL || hs_streaming[0] == NULL ||
+- hs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER)
++ hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
+ goto error;
+
+ uvc->desc.control = control;
+--- a/drivers/usb/gadget/f_uvc.h
++++ b/drivers/usb/gadget/f_uvc.h
+@@ -15,357 +15,7 @@
+ #define _F_UVC_H_
+
+ #include <linux/usb/composite.h>
+-
+-#define USB_CLASS_VIDEO_CONTROL 1
+-#define USB_CLASS_VIDEO_STREAMING 2
+-
+-struct uvc_descriptor_header {
+- __u8 bLength;
+- __u8 bDescriptorType;
+- __u8 bDescriptorSubType;
+-} __attribute__ ((packed));
+-
+-struct uvc_header_descriptor {
+- __u8 bLength;
+- __u8 bDescriptorType;
+- __u8 bDescriptorSubType;
+- __u16 bcdUVC;
+- __u16 wTotalLength;
+- __u32 dwClockFrequency;
+- __u8 bInCollection;
+- __u8 baInterfaceNr[];
+-} __attribute__((__packed__));
+-
+-#define UVC_HEADER_DESCRIPTOR(n) uvc_header_descriptor_##n
+-
+-#define DECLARE_UVC_HEADER_DESCRIPTOR(n) \
+-struct UVC_HEADER_DESCRIPTOR(n) { \
+- __u8 bLength; \
+- __u8 bDescriptorType; \
+- __u8 bDescriptorSubType; \
+- __u16 bcdUVC; \
+- __u16 wTotalLength; \
+- __u32 dwClockFrequency; \
+- __u8 bInCollection; \
+- __u8 baInterfaceNr[n]; \
+-} __attribute__ ((packed))
+-
+-struct uvc_input_terminal_descriptor {
+- __u8 bLength;
+- __u8 bDescriptorType;
+- __u8 bDescriptorSubType;
+- __u8 bTerminalID;
+- __u16 wTerminalType;
+- __u8 bAssocTerminal;
+- __u8 iTerminal;
+-} __attribute__((__packed__));
+-
+-struct uvc_output_terminal_descriptor {
+- __u8 bLength;
+- __u8 bDescriptorType;
+- __u8 bDescriptorSubType;
+- __u8 bTerminalID;
+- __u16 wTerminalType;
+- __u8 bAssocTerminal;
+- __u8 bSourceID;
+- __u8 iTerminal;
+-} __attribute__((__packed__));
+-
+-struct uvc_camera_terminal_descriptor {
+- __u8 bLength;
+- __u8 bDescriptorType;
+- __u8 bDescriptorSubType;
+- __u8 bTerminalID;
+- __u16 wTerminalType;
+- __u8 bAssocTerminal;
+- __u8 iTerminal;
+- __u16 wObjectiveFocalLengthMin;
+- __u16 wObjectiveFocalLengthMax;
+- __u16 wOcularFocalLength;
+- __u8 bControlSize;
+- __u8 bmControls[3];
+-} __attribute__((__packed__));
+-
+-struct uvc_selector_unit_descriptor {
+- __u8 bLength;
+- __u8 bDescriptorType;
+- __u8 bDescriptorSubType;
+- __u8 bUnitID;
+- __u8 bNrInPins;
+- __u8 baSourceID[0];
+- __u8 iSelector;
+-} __attribute__((__packed__));
+-
+-#define UVC_SELECTOR_UNIT_DESCRIPTOR(n) \
+- uvc_selector_unit_descriptor_##n
+-
+-#define DECLARE_UVC_SELECTOR_UNIT_DESCRIPTOR(n) \
+-struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) { \
+- __u8 bLength; \
+- __u8 bDescriptorType; \
+- __u8 bDescriptorSubType; \
+- __u8 bUnitID; \
+- __u8 bNrInPins; \
+- __u8 baSourceID[n]; \
+- __u8 iSelector; \
+-} __attribute__ ((packed))
+-
+-struct uvc_processing_unit_descriptor {
+- __u8 bLength;
+- __u8 bDescriptorType;
+- __u8 bDescriptorSubType;
+- __u8 bUnitID;
+- __u8 bSourceID;
+- __u16 wMaxMultiplier;
+- __u8 bControlSize;
+- __u8 bmControls[2];
+- __u8 iProcessing;
+-} __attribute__((__packed__));
+-
+-struct uvc_extension_unit_descriptor {
+- __u8 bLength;
+- __u8 bDescriptorType;
+- __u8 bDescriptorSubType;
+- __u8 bUnitID;
+- __u8 guidExtensionCode[16];
+- __u8 bNumControls;
+- __u8 bNrInPins;
+- __u8 baSourceID[0];
+- __u8 bControlSize;
+- __u8 bmControls[0];
+- __u8 iExtension;
+-} __attribute__((__packed__));
+-
+-#define UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
+- uvc_extension_unit_descriptor_##p_##n
+-
+-#define DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
+-struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) { \
+- __u8 bLength; \
+- __u8 bDescriptorType; \
+- __u8 bDescriptorSubType; \
+- __u8 bUnitID; \
+- __u8 guidExtensionCode[16]; \
+- __u8 bNumControls; \
+- __u8 bNrInPins; \
+- __u8 baSourceID[p]; \
+- __u8 bControlSize; \
+- __u8 bmControls[n]; \
+- __u8 iExtension; \
+-} __attribute__ ((packed))
+-
+-struct uvc_control_endpoint_descriptor {
+- __u8 bLength;
+- __u8 bDescriptorType;
+- __u8 bDescriptorSubType;
+- __u16 wMaxTransferSize;
+-} __attribute__((__packed__));
+-
+-#define UVC_DT_HEADER 1
+-#define UVC_DT_INPUT_TERMINAL 2
+-#define UVC_DT_OUTPUT_TERMINAL 3
+-#define UVC_DT_SELECTOR_UNIT 4
+-#define UVC_DT_PROCESSING_UNIT 5
+-#define UVC_DT_EXTENSION_UNIT 6
+-
+-#define UVC_DT_HEADER_SIZE(n) (12+(n))
+-#define UVC_DT_INPUT_TERMINAL_SIZE 8
+-#define UVC_DT_OUTPUT_TERMINAL_SIZE 9
+-#define UVC_DT_CAMERA_TERMINAL_SIZE(n) (15+(n))
+-#define UVC_DT_SELECTOR_UNIT_SIZE(n) (6+(n))
+-#define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n))
+-#define UVC_DT_EXTENSION_UNIT_SIZE(p,n) (24+(p)+(n))
+-#define UVC_DT_CONTROL_ENDPOINT_SIZE 5
+-
+-struct uvc_input_header_descriptor {
+- __u8 bLength;
+- __u8 bDescriptorType;
+- __u8 bDescriptorSubType;
+- __u8 bNumFormats;
+- __u16 wTotalLength;
+- __u8 bEndpointAddress;
+- __u8 bmInfo;
+- __u8 bTerminalLink;
+- __u8 bStillCaptureMethod;
+- __u8 bTriggerSupport;
+- __u8 bTriggerUsage;
+- __u8 bControlSize;
+- __u8 bmaControls[];
+-} __attribute__((__packed__));
+-
+-#define UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
+- uvc_input_header_descriptor_##n_##p
+-
+-#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
+-struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { \
+- __u8 bLength; \
+- __u8 bDescriptorType; \
+- __u8 bDescriptorSubType; \
+- __u8 bNumFormats; \
+- __u16 wTotalLength; \
+- __u8 bEndpointAddress; \
+- __u8 bmInfo; \
+- __u8 bTerminalLink; \
+- __u8 bStillCaptureMethod; \
+- __u8 bTriggerSupport; \
+- __u8 bTriggerUsage; \
+- __u8 bControlSize; \
+- __u8 bmaControls[p][n]; \
+-} __attribute__ ((packed))
+-
+-struct uvc_output_header_descriptor {
+- __u8 bLength;
+- __u8 bDescriptorType;
+- __u8 bDescriptorSubType;
+- __u8 bNumFormats;
+- __u16 wTotalLength;
+- __u8 bEndpointAddress;
+- __u8 bTerminalLink;
+- __u8 bControlSize;
+- __u8 bmaControls[];
+-} __attribute__((__packed__));
+-
+-#define UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
+- uvc_output_header_descriptor_##n_##p
+-
+-#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
+-struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { \
+- __u8 bLength; \
+- __u8 bDescriptorType; \
+- __u8 bDescriptorSubType; \
+- __u8 bNumFormats; \
+- __u16 wTotalLength; \
+- __u8 bEndpointAddress; \
+- __u8 bTerminalLink; \
+- __u8 bControlSize; \
+- __u8 bmaControls[p][n]; \
+-} __attribute__ ((packed))
+-
+-struct uvc_format_uncompressed {
+- __u8 bLength;
+- __u8 bDescriptorType;
+- __u8 bDescriptorSubType;
+- __u8 bFormatIndex;
+- __u8 bNumFrameDescriptors;
+- __u8 guidFormat[16];
+- __u8 bBitsPerPixel;
+- __u8 bDefaultFrameIndex;
+- __u8 bAspectRatioX;
+- __u8 bAspectRatioY;
+- __u8 bmInterfaceFlags;
+- __u8 bCopyProtect;
+-} __attribute__((__packed__));
+-
+-struct uvc_frame_uncompressed {
+- __u8 bLength;
+- __u8 bDescriptorType;
+- __u8 bDescriptorSubType;
+- __u8 bFrameIndex;
+- __u8 bmCapabilities;
+- __u16 wWidth;
+- __u16 wHeight;
+- __u32 dwMinBitRate;
+- __u32 dwMaxBitRate;
+- __u32 dwMaxVideoFrameBufferSize;
+- __u32 dwDefaultFrameInterval;
+- __u8 bFrameIntervalType;
+- __u32 dwFrameInterval[];
+-} __attribute__((__packed__));
+-
+-#define UVC_FRAME_UNCOMPRESSED(n) \
+- uvc_frame_uncompressed_##n
+-
+-#define DECLARE_UVC_FRAME_UNCOMPRESSED(n) \
+-struct UVC_FRAME_UNCOMPRESSED(n) { \
+- __u8 bLength; \
+- __u8 bDescriptorType; \
+- __u8 bDescriptorSubType; \
+- __u8 bFrameIndex; \
+- __u8 bmCapabilities; \
+- __u16 wWidth; \
+- __u16 wHeight; \
+- __u32 dwMinBitRate; \
+- __u32 dwMaxBitRate; \
+- __u32 dwMaxVideoFrameBufferSize; \
+- __u32 dwDefaultFrameInterval; \
+- __u8 bFrameIntervalType; \
+- __u32 dwFrameInterval[n]; \
+-} __attribute__ ((packed))
+-
+-struct uvc_format_mjpeg {
+- __u8 bLength;
+- __u8 bDescriptorType;
+- __u8 bDescriptorSubType;
+- __u8 bFormatIndex;
+- __u8 bNumFrameDescriptors;
+- __u8 bmFlags;
+- __u8 bDefaultFrameIndex;
+- __u8 bAspectRatioX;
+- __u8 bAspectRatioY;
+- __u8 bmInterfaceFlags;
+- __u8 bCopyProtect;
+-} __attribute__((__packed__));
+-
+-struct uvc_frame_mjpeg {
+- __u8 bLength;
+- __u8 bDescriptorType;
+- __u8 bDescriptorSubType;
+- __u8 bFrameIndex;
+- __u8 bmCapabilities;
+- __u16 wWidth;
+- __u16 wHeight;
+- __u32 dwMinBitRate;
+- __u32 dwMaxBitRate;
+- __u32 dwMaxVideoFrameBufferSize;
+- __u32 dwDefaultFrameInterval;
+- __u8 bFrameIntervalType;
+- __u32 dwFrameInterval[];
+-} __attribute__((__packed__));
+-
+-#define UVC_FRAME_MJPEG(n) \
+- uvc_frame_mjpeg_##n
+-
+-#define DECLARE_UVC_FRAME_MJPEG(n) \
+-struct UVC_FRAME_MJPEG(n) { \
+- __u8 bLength; \
+- __u8 bDescriptorType; \
+- __u8 bDescriptorSubType; \
+- __u8 bFrameIndex; \
+- __u8 bmCapabilities; \
+- __u16 wWidth; \
+- __u16 wHeight; \
+- __u32 dwMinBitRate; \
+- __u32 dwMaxBitRate; \
+- __u32 dwMaxVideoFrameBufferSize; \
+- __u32 dwDefaultFrameInterval; \
+- __u8 bFrameIntervalType; \
+- __u32 dwFrameInterval[n]; \
+-} __attribute__ ((packed))
+-
+-struct uvc_color_matching_descriptor {
+- __u8 bLength;
+- __u8 bDescriptorType;
+- __u8 bDescriptorSubType;
+- __u8 bColorPrimaries;
+- __u8 bTransferCharacteristics;
+- __u8 bMatrixCoefficients;
+-} __attribute__((__packed__));
+-
+-#define UVC_DT_INPUT_HEADER 1
+-#define UVC_DT_OUTPUT_HEADER 2
+-#define UVC_DT_FORMAT_UNCOMPRESSED 4
+-#define UVC_DT_FRAME_UNCOMPRESSED 5
+-#define UVC_DT_FORMAT_MJPEG 6
+-#define UVC_DT_FRAME_MJPEG 7
+-#define UVC_DT_COLOR_MATCHING 13
+-
+-#define UVC_DT_INPUT_HEADER_SIZE(n, p) (13+(n*p))
+-#define UVC_DT_OUTPUT_HEADER_SIZE(n, p) (9+(n*p))
+-#define UVC_DT_FORMAT_UNCOMPRESSED_SIZE 27
+-#define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n) (26+4*(n))
+-#define UVC_DT_FORMAT_MJPEG_SIZE 11
+-#define UVC_DT_FRAME_MJPEG_SIZE(n) (26+4*(n))
+-#define UVC_DT_COLOR_MATCHING_SIZE 6
++#include <linux/usb/video.h>
+
+ extern int uvc_bind_config(struct usb_configuration *c,
+ const struct uvc_descriptor_header * const *control,
+--- a/drivers/usb/gadget/uvc.h
++++ b/drivers/usb/gadget/uvc.h
+@@ -48,39 +48,6 @@ struct uvc_event
+ #define UVC_INTF_STREAMING 1
+
+ /* ------------------------------------------------------------------------
+- * UVC constants & structures
+- */
+-
+-/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
+-#define UVC_STREAM_EOH (1 << 7)
+-#define UVC_STREAM_ERR (1 << 6)
+-#define UVC_STREAM_STI (1 << 5)
+-#define UVC_STREAM_RES (1 << 4)
+-#define UVC_STREAM_SCR (1 << 3)
+-#define UVC_STREAM_PTS (1 << 2)
+-#define UVC_STREAM_EOF (1 << 1)
+-#define UVC_STREAM_FID (1 << 0)
+-
+-struct uvc_streaming_control {
+- __u16 bmHint;
+- __u8 bFormatIndex;
+- __u8 bFrameIndex;
+- __u32 dwFrameInterval;
+- __u16 wKeyFrameRate;
+- __u16 wPFrameRate;
+- __u16 wCompQuality;
+- __u16 wCompWindowSize;
+- __u16 wDelay;
+- __u32 dwMaxVideoFrameSize;
+- __u32 dwMaxPayloadTransferSize;
+- __u32 dwClockFrequency;
+- __u8 bmFramingInfo;
+- __u8 bPreferedVersion;
+- __u8 bMinVersion;
+- __u8 bMaxVersion;
+-} __attribute__((__packed__));
+-
+-/* ------------------------------------------------------------------------
+ * Debugging, printing and logging
+ */
+
+@@ -137,9 +104,6 @@ extern unsigned int uvc_trace_param;
+ #define UVC_MAX_REQUEST_SIZE 64
+ #define UVC_MAX_EVENTS 4
+
+-#define USB_DT_INTERFACE_ASSOCIATION_SIZE 8
+-#define USB_CLASS_MISC 0xef
+-
+ /* ------------------------------------------------------------------------
+ * Structures
+ */
+--- a/drivers/usb/gadget/webcam.c
++++ b/drivers/usb/gadget/webcam.c
+@@ -90,7 +90,7 @@ DECLARE_UVC_HEADER_DESCRIPTOR(1);
+ static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
+ .bLength = UVC_DT_HEADER_SIZE(1),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+- .bDescriptorSubType = UVC_DT_HEADER,
++ .bDescriptorSubType = UVC_VC_HEADER,
+ .bcdUVC = cpu_to_le16(0x0100),
+ .wTotalLength = 0, /* dynamic */
+ .dwClockFrequency = cpu_to_le32(48000000),
+@@ -101,7 +101,7 @@ static const struct UVC_HEADER_DESCRIPTO
+ static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
+ .bLength = UVC_DT_CAMERA_TERMINAL_SIZE(3),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+- .bDescriptorSubType = UVC_DT_INPUT_TERMINAL,
++ .bDescriptorSubType = UVC_VC_INPUT_TERMINAL,
+ .bTerminalID = 1,
+ .wTerminalType = cpu_to_le16(0x0201),
+ .bAssocTerminal = 0,
+@@ -118,7 +118,7 @@ static const struct uvc_camera_terminal_
+ static const struct uvc_processing_unit_descriptor uvc_processing = {
+ .bLength = UVC_DT_PROCESSING_UNIT_SIZE(2),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+- .bDescriptorSubType = UVC_DT_PROCESSING_UNIT,
++ .bDescriptorSubType = UVC_VC_PROCESSING_UNIT,
+ .bUnitID = 2,
+ .bSourceID = 1,
+ .wMaxMultiplier = cpu_to_le16(16*1024),
+@@ -131,7 +131,7 @@ static const struct uvc_processing_unit_
+ static const struct uvc_output_terminal_descriptor uvc_output_terminal = {
+ .bLength = UVC_DT_OUTPUT_TERMINAL_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+- .bDescriptorSubType = UVC_DT_OUTPUT_TERMINAL,
++ .bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL,
+ .bTerminalID = 3,
+ .wTerminalType = cpu_to_le16(0x0101),
+ .bAssocTerminal = 0,
+@@ -144,7 +144,7 @@ DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 2
+ static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
+ .bLength = UVC_DT_INPUT_HEADER_SIZE(1, 2),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+- .bDescriptorSubType = UVC_DT_INPUT_HEADER,
++ .bDescriptorSubType = UVC_VS_INPUT_HEADER,
+ .bNumFormats = 2,
+ .wTotalLength = 0, /* dynamic */
+ .bEndpointAddress = 0, /* dynamic */
+@@ -161,7 +161,7 @@ static const struct UVC_INPUT_HEADER_DES
+ static const struct uvc_format_uncompressed uvc_format_yuv = {
+ .bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+- .bDescriptorSubType = UVC_DT_FORMAT_UNCOMPRESSED,
++ .bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED,
+ .bFormatIndex = 1,
+ .bNumFrameDescriptors = 2,
+ .guidFormat =
+@@ -181,7 +181,7 @@ DECLARE_UVC_FRAME_UNCOMPRESSED(3);
+ static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
+ .bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+- .bDescriptorSubType = UVC_DT_FRAME_UNCOMPRESSED,
++ .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED,
+ .bFrameIndex = 1,
+ .bmCapabilities = 0,
+ .wWidth = cpu_to_le16(640),
+@@ -199,7 +199,7 @@ static const struct UVC_FRAME_UNCOMPRESS
+ static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
+ .bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+- .bDescriptorSubType = UVC_DT_FRAME_UNCOMPRESSED,
++ .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED,
+ .bFrameIndex = 2,
+ .bmCapabilities = 0,
+ .wWidth = cpu_to_le16(1280),
+@@ -215,7 +215,7 @@ static const struct UVC_FRAME_UNCOMPRESS
+ static const struct uvc_format_mjpeg uvc_format_mjpg = {
+ .bLength = UVC_DT_FORMAT_MJPEG_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+- .bDescriptorSubType = UVC_DT_FORMAT_MJPEG,
++ .bDescriptorSubType = UVC_VS_FORMAT_MJPEG,
+ .bFormatIndex = 2,
+ .bNumFrameDescriptors = 2,
+ .bmFlags = 0,
+@@ -232,7 +232,7 @@ DECLARE_UVC_FRAME_MJPEG(3);
+ static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
+ .bLength = UVC_DT_FRAME_MJPEG_SIZE(3),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+- .bDescriptorSubType = UVC_DT_FRAME_MJPEG,
++ .bDescriptorSubType = UVC_VS_FRAME_MJPEG,
+ .bFrameIndex = 1,
+ .bmCapabilities = 0,
+ .wWidth = cpu_to_le16(640),
+@@ -250,7 +250,7 @@ static const struct UVC_FRAME_MJPEG(3) u
+ static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
+ .bLength = UVC_DT_FRAME_MJPEG_SIZE(1),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+- .bDescriptorSubType = UVC_DT_FRAME_MJPEG,
++ .bDescriptorSubType = UVC_VS_FRAME_MJPEG,
+ .bFrameIndex = 2,
+ .bmCapabilities = 0,
+ .wWidth = cpu_to_le16(1280),
+@@ -266,7 +266,7 @@ static const struct UVC_FRAME_MJPEG(1) u
+ static const struct uvc_color_matching_descriptor uvc_color_matching = {
+ .bLength = UVC_DT_COLOR_MATCHING_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+- .bDescriptorSubType = UVC_DT_COLOR_MATCHING,
++ .bDescriptorSubType = UVC_VS_COLORFORMAT,
+ .bColorPrimaries = 1,
+ .bTransferCharacteristics = 1,
+ .bMatrixCoefficients = 4,
+--- a/include/linux/usb/video.h
++++ b/include/linux/usb/video.h
+@@ -160,5 +160,402 @@
+ #define UVC_STATUS_TYPE_CONTROL 1
+ #define UVC_STATUS_TYPE_STREAMING 2
+
++/* 2.4.3.3. Payload Header Information */
++#define UVC_STREAM_EOH (1 << 7)
++#define UVC_STREAM_ERR (1 << 6)
++#define UVC_STREAM_STI (1 << 5)
++#define UVC_STREAM_RES (1 << 4)
++#define UVC_STREAM_SCR (1 << 3)
++#define UVC_STREAM_PTS (1 << 2)
++#define UVC_STREAM_EOF (1 << 1)
++#define UVC_STREAM_FID (1 << 0)
++
++/* ------------------------------------------------------------------------
++ * UVC structures
++ */
++
++/* All UVC descriptors have these 3 fields at the beginning */
++struct uvc_descriptor_header {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubType;
++} __attribute__((packed));
++
++/* 3.7.2. Video Control Interface Header Descriptor */
++struct uvc_header_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubType;
++ __u16 bcdUVC;
++ __u16 wTotalLength;
++ __u32 dwClockFrequency;
++ __u8 bInCollection;
++ __u8 baInterfaceNr[];
++} __attribute__((__packed__));
++
++#define UVC_DT_HEADER_SIZE(n) (12+(n))
++
++#define UVC_HEADER_DESCRIPTOR(n) \
++ uvc_header_descriptor_##n
++
++#define DECLARE_UVC_HEADER_DESCRIPTOR(n) \
++struct UVC_HEADER_DESCRIPTOR(n) { \
++ __u8 bLength; \
++ __u8 bDescriptorType; \
++ __u8 bDescriptorSubType; \
++ __u16 bcdUVC; \
++ __u16 wTotalLength; \
++ __u32 dwClockFrequency; \
++ __u8 bInCollection; \
++ __u8 baInterfaceNr[n]; \
++} __attribute__ ((packed))
++
++/* 3.7.2.1. Input Terminal Descriptor */
++struct uvc_input_terminal_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubType;
++ __u8 bTerminalID;
++ __u16 wTerminalType;
++ __u8 bAssocTerminal;
++ __u8 iTerminal;
++} __attribute__((__packed__));
++
++#define UVC_DT_INPUT_TERMINAL_SIZE 8
++
++/* 3.7.2.2. Output Terminal Descriptor */
++struct uvc_output_terminal_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubType;
++ __u8 bTerminalID;
++ __u16 wTerminalType;
++ __u8 bAssocTerminal;
++ __u8 bSourceID;
++ __u8 iTerminal;
++} __attribute__((__packed__));
++
++#define UVC_DT_OUTPUT_TERMINAL_SIZE 9
++
++/* 3.7.2.3. Camera Terminal Descriptor */
++struct uvc_camera_terminal_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubType;
++ __u8 bTerminalID;
++ __u16 wTerminalType;
++ __u8 bAssocTerminal;
++ __u8 iTerminal;
++ __u16 wObjectiveFocalLengthMin;
++ __u16 wObjectiveFocalLengthMax;
++ __u16 wOcularFocalLength;
++ __u8 bControlSize;
++ __u8 bmControls[3];
++} __attribute__((__packed__));
++
++#define UVC_DT_CAMERA_TERMINAL_SIZE(n) (15+(n))
++
++/* 3.7.2.4. Selector Unit Descriptor */
++struct uvc_selector_unit_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubType;
++ __u8 bUnitID;
++ __u8 bNrInPins;
++ __u8 baSourceID[0];
++ __u8 iSelector;
++} __attribute__((__packed__));
++
++#define UVC_DT_SELECTOR_UNIT_SIZE(n) (6+(n))
++
++#define UVC_SELECTOR_UNIT_DESCRIPTOR(n) \
++ uvc_selector_unit_descriptor_##n
++
++#define DECLARE_UVC_SELECTOR_UNIT_DESCRIPTOR(n) \
++struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) { \
++ __u8 bLength; \
++ __u8 bDescriptorType; \
++ __u8 bDescriptorSubType; \
++ __u8 bUnitID; \
++ __u8 bNrInPins; \
++ __u8 baSourceID[n]; \
++ __u8 iSelector; \
++} __attribute__ ((packed))
++
++/* 3.7.2.5. Processing Unit Descriptor */
++struct uvc_processing_unit_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubType;
++ __u8 bUnitID;
++ __u8 bSourceID;
++ __u16 wMaxMultiplier;
++ __u8 bControlSize;
++ __u8 bmControls[2];
++ __u8 iProcessing;
++} __attribute__((__packed__));
++
++#define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n))
++
++/* 3.7.2.6. Extension Unit Descriptor */
++struct uvc_extension_unit_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubType;
++ __u8 bUnitID;
++ __u8 guidExtensionCode[16];
++ __u8 bNumControls;
++ __u8 bNrInPins;
++ __u8 baSourceID[0];
++ __u8 bControlSize;
++ __u8 bmControls[0];
++ __u8 iExtension;
++} __attribute__((__packed__));
++
++#define UVC_DT_EXTENSION_UNIT_SIZE(p, n) (24+(p)+(n))
++
++#define UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
++ uvc_extension_unit_descriptor_##p_##n
++
++#define DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
++struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) { \
++ __u8 bLength; \
++ __u8 bDescriptorType; \
++ __u8 bDescriptorSubType; \
++ __u8 bUnitID; \
++ __u8 guidExtensionCode[16]; \
++ __u8 bNumControls; \
++ __u8 bNrInPins; \
++ __u8 baSourceID[p]; \
++ __u8 bControlSize; \
++ __u8 bmControls[n]; \
++ __u8 iExtension; \
++} __attribute__ ((packed))
++
++/* 3.8.2.2. Video Control Interrupt Endpoint Descriptor */
++struct uvc_control_endpoint_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubType;
++ __u16 wMaxTransferSize;
++} __attribute__((__packed__));
++
++#define UVC_DT_CONTROL_ENDPOINT_SIZE 5
++
++/* 3.9.2.1. Input Header Descriptor */
++struct uvc_input_header_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubType;
++ __u8 bNumFormats;
++ __u16 wTotalLength;
++ __u8 bEndpointAddress;
++ __u8 bmInfo;
++ __u8 bTerminalLink;
++ __u8 bStillCaptureMethod;
++ __u8 bTriggerSupport;
++ __u8 bTriggerUsage;
++ __u8 bControlSize;
++ __u8 bmaControls[];
++} __attribute__((__packed__));
++
++#define UVC_DT_INPUT_HEADER_SIZE(n, p) (13+(n*p))
++
++#define UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
++ uvc_input_header_descriptor_##n_##p
++
++#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
++struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { \
++ __u8 bLength; \
++ __u8 bDescriptorType; \
++ __u8 bDescriptorSubType; \
++ __u8 bNumFormats; \
++ __u16 wTotalLength; \
++ __u8 bEndpointAddress; \
++ __u8 bmInfo; \
++ __u8 bTerminalLink; \
++ __u8 bStillCaptureMethod; \
++ __u8 bTriggerSupport; \
++ __u8 bTriggerUsage; \
++ __u8 bControlSize; \
++ __u8 bmaControls[p][n]; \
++} __attribute__ ((packed))
++
++/* 3.9.2.2. Output Header Descriptor */
++struct uvc_output_header_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubType;
++ __u8 bNumFormats;
++ __u16 wTotalLength;
++ __u8 bEndpointAddress;
++ __u8 bTerminalLink;
++ __u8 bControlSize;
++ __u8 bmaControls[];
++} __attribute__((__packed__));
++
++#define UVC_DT_OUTPUT_HEADER_SIZE(n, p) (9+(n*p))
++
++#define UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
++ uvc_output_header_descriptor_##n_##p
++
++#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
++struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { \
++ __u8 bLength; \
++ __u8 bDescriptorType; \
++ __u8 bDescriptorSubType; \
++ __u8 bNumFormats; \
++ __u16 wTotalLength; \
++ __u8 bEndpointAddress; \
++ __u8 bTerminalLink; \
++ __u8 bControlSize; \
++ __u8 bmaControls[p][n]; \
++} __attribute__ ((packed))
++
++/* 3.9.2.6. Color matching descriptor */
++struct uvc_color_matching_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubType;
++ __u8 bColorPrimaries;
++ __u8 bTransferCharacteristics;
++ __u8 bMatrixCoefficients;
++} __attribute__((__packed__));
++
++#define UVC_DT_COLOR_MATCHING_SIZE 6
++
++/* 4.3.1.1. Video Probe and Commit Controls */
++struct uvc_streaming_control {
++ __u16 bmHint;
++ __u8 bFormatIndex;
++ __u8 bFrameIndex;
++ __u32 dwFrameInterval;
++ __u16 wKeyFrameRate;
++ __u16 wPFrameRate;
++ __u16 wCompQuality;
++ __u16 wCompWindowSize;
++ __u16 wDelay;
++ __u32 dwMaxVideoFrameSize;
++ __u32 dwMaxPayloadTransferSize;
++ __u32 dwClockFrequency;
++ __u8 bmFramingInfo;
++ __u8 bPreferedVersion;
++ __u8 bMinVersion;
++ __u8 bMaxVersion;
++} __attribute__((__packed__));
++
++/* Uncompressed Payload - 3.1.1. Uncompressed Video Format Descriptor */
++struct uvc_format_uncompressed {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubType;
++ __u8 bFormatIndex;
++ __u8 bNumFrameDescriptors;
++ __u8 guidFormat[16];
++ __u8 bBitsPerPixel;
++ __u8 bDefaultFrameIndex;
++ __u8 bAspectRatioX;
++ __u8 bAspectRatioY;
++ __u8 bmInterfaceFlags;
++ __u8 bCopyProtect;
++} __attribute__((__packed__));
++
++#define UVC_DT_FORMAT_UNCOMPRESSED_SIZE 27
++
++/* Uncompressed Payload - 3.1.2. Uncompressed Video Frame Descriptor */
++struct uvc_frame_uncompressed {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubType;
++ __u8 bFrameIndex;
++ __u8 bmCapabilities;
++ __u16 wWidth;
++ __u16 wHeight;
++ __u32 dwMinBitRate;
++ __u32 dwMaxBitRate;
++ __u32 dwMaxVideoFrameBufferSize;
++ __u32 dwDefaultFrameInterval;
++ __u8 bFrameIntervalType;
++ __u32 dwFrameInterval[];
++} __attribute__((__packed__));
++
++#define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n) (26+4*(n))
++
++#define UVC_FRAME_UNCOMPRESSED(n) \
++ uvc_frame_uncompressed_##n
++
++#define DECLARE_UVC_FRAME_UNCOMPRESSED(n) \
++struct UVC_FRAME_UNCOMPRESSED(n) { \
++ __u8 bLength; \
++ __u8 bDescriptorType; \
++ __u8 bDescriptorSubType; \
++ __u8 bFrameIndex; \
++ __u8 bmCapabilities; \
++ __u16 wWidth; \
++ __u16 wHeight; \
++ __u32 dwMinBitRate; \
++ __u32 dwMaxBitRate; \
++ __u32 dwMaxVideoFrameBufferSize; \
++ __u32 dwDefaultFrameInterval; \
++ __u8 bFrameIntervalType; \
++ __u32 dwFrameInterval[n]; \
++} __attribute__ ((packed))
++
++/* MJPEG Payload - 3.1.1. MJPEG Video Format Descriptor */
++struct uvc_format_mjpeg {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubType;
++ __u8 bFormatIndex;
++ __u8 bNumFrameDescriptors;
++ __u8 bmFlags;
++ __u8 bDefaultFrameIndex;
++ __u8 bAspectRatioX;
++ __u8 bAspectRatioY;
++ __u8 bmInterfaceFlags;
++ __u8 bCopyProtect;
++} __attribute__((__packed__));
++
++#define UVC_DT_FORMAT_MJPEG_SIZE 11
++
++/* MJPEG Payload - 3.1.2. MJPEG Video Frame Descriptor */
++struct uvc_frame_mjpeg {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubType;
++ __u8 bFrameIndex;
++ __u8 bmCapabilities;
++ __u16 wWidth;
++ __u16 wHeight;
++ __u32 dwMinBitRate;
++ __u32 dwMaxBitRate;
++ __u32 dwMaxVideoFrameBufferSize;
++ __u32 dwDefaultFrameInterval;
++ __u8 bFrameIntervalType;
++ __u32 dwFrameInterval[];
++} __attribute__((__packed__));
++
++#define UVC_DT_FRAME_MJPEG_SIZE(n) (26+4*(n))
++
++#define UVC_FRAME_MJPEG(n) \
++ uvc_frame_mjpeg_##n
++
++#define DECLARE_UVC_FRAME_MJPEG(n) \
++struct UVC_FRAME_MJPEG(n) { \
++ __u8 bLength; \
++ __u8 bDescriptorType; \
++ __u8 bDescriptorSubType; \
++ __u8 bFrameIndex; \
++ __u8 bmCapabilities; \
++ __u16 wWidth; \
++ __u16 wHeight; \
++ __u32 dwMinBitRate; \
++ __u32 dwMaxBitRate; \
++ __u32 dwMaxVideoFrameBufferSize; \
++ __u32 dwDefaultFrameInterval; \
++ __u8 bFrameIntervalType; \
++ __u32 dwFrameInterval[n]; \
++} __attribute__ ((packed))
++
+ #endif /* __LINUX_USB_VIDEO_H */
+