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