diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-25 15:42:36 -0800 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-25 15:42:36 -0800 |
| commit | c2740cbf8a1afa5e0699896629210858923e98e1 (patch) | |
| tree | 99c2968ac29219d4246e3c08194b54fb54694b76 | |
| parent | 6f1bc475e2d301aa2909e1bd3c5105e51851d4b8 (diff) | |
| download | patches-c2740cbf8a1afa5e0699896629210858923e98e1.tar.gz | |
more patches added
16 files changed, 1808 insertions, 1 deletions
diff --git a/driver-core.current/driver-core-fix-kernel-doc-parameter-name.patch b/driver-core.current/driver-core-fix-kernel-doc-parameter-name.patch new file mode 100644 index 00000000000000..a5725cb84e5f67 --- /dev/null +++ b/driver-core.current/driver-core-fix-kernel-doc-parameter-name.patch @@ -0,0 +1,35 @@ +From randy.dunlap@oracle.com Sun Jan 25 15:22:23 2009 +From: Randy Dunlap <randy.dunlap@oracle.com> +Date: Tue, 20 Jan 2009 16:29:13 -0800 +Subject: driver-core: fix kernel-doc parameter name +To: lkml <linux-kernel@vger.kernel.org> +Cc: gregkh <greg@kroah.com>, Mark McLoughlin <markmc@redhat.com> +Message-ID: <20090120162913.fffe3305.randy.dunlap@oracle.com> + + +From: Randy Dunlap <randy.dunlap@oracle.com> + +Fix function parameter name in kernel-doc: + +Warning(linux-next-20090120//drivers/base/core.c:1289): No description found for parameter 'dev' +Warning(linux-next-20090120//drivers/base/core.c:1289): Excess function parameter 'root' description in 'root_device_unregister' + +Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> +Acked-by: Mark McLoughlin <markmc@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/base/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -1280,7 +1280,7 @@ EXPORT_SYMBOL_GPL(__root_device_register + + /** + * root_device_unregister - unregister and free a root device +- * @root: device going away. ++ * @dev: device going away + * + * This function unregisters and cleans up a device that was created by + * root_device_register(). diff --git a/driver-core/driver-core-check-bus-match-without-holding-device-lock.patch b/driver-core/driver-core-check-bus-match-without-holding-device-lock.patch new file mode 100644 index 00000000000000..96f23d21a7f2b0 --- /dev/null +++ b/driver-core/driver-core-check-bus-match-without-holding-device-lock.patch @@ -0,0 +1,115 @@ +From tom.leiming@gmail.com Sun Jan 25 15:25:18 2009 +From: tom.leiming@gmail.com +Date: Wed, 21 Jan 2009 23:27:47 +0800 +Subject: driver core: check bus->match without holding device lock +To: kay.sievers@vrfy.org, greg@kroah.com +Cc: cornelia.huck@de.ibm.com, arjan@linux.intel.com, Ming Lei <tom.leiming@gmail.com> +Message-ID: <1232551667-4829-1-git-send-email-tom.leiming@gmail.com> + + +From: Ming Lei <tom.leiming@gmail.com> + +This patch moves bus->match out from driver_probe_device and +does not hold device lock to check the match between a device +and a driver. + +The idea has been verified by the commit 6cd495860901, +which leads to a faster boot. But the commit 6cd495860901 has +the following drawbacks: 1),only does the quick check in +the path of __driver_attach->driver_probe_device, not in other +paths; 2),for a matched device and driver, check the same match +twice. It is a waste of cpu ,especially for some drivers with long +device id table (eg. usb-storage driver). + +This patch adds a helper of driver_match_device to check the match +in all paths, and testes the match only once. + +Signed-off-by: Ming Lei <tom.leiming@gmail.com> +Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/base/base.h | 5 +++++ + drivers/base/bus.c | 2 +- + drivers/base/dd.c | 19 +++++++------------ + 3 files changed, 13 insertions(+), 13 deletions(-) + +--- a/drivers/base/base.h ++++ b/drivers/base/base.h +@@ -86,6 +86,11 @@ extern void bus_remove_driver(struct dev + + extern void driver_detach(struct device_driver *drv); + extern int driver_probe_device(struct device_driver *drv, struct device *dev); ++static inline int driver_match_device(struct device_driver *drv, ++ struct device *dev) ++{ ++ return drv->bus->match && drv->bus->match(dev, drv); ++} + + extern void sysdev_shutdown(void); + extern int sysdev_suspend(pm_message_t state); +--- a/drivers/base/bus.c ++++ b/drivers/base/bus.c +@@ -198,7 +198,7 @@ static ssize_t driver_bind(struct device + int err = -ENODEV; + + dev = bus_find_device_by_name(bus, NULL, buf); +- if (dev && dev->driver == NULL) { ++ if (dev && dev->driver == NULL && driver_match_device(drv, dev)) { + if (dev->parent) /* Needed for USB */ + down(&dev->parent->sem); + down(&dev->sem); +--- a/drivers/base/dd.c ++++ b/drivers/base/dd.c +@@ -172,14 +172,8 @@ int driver_probe_done(void) + * @drv: driver to bind a device to + * @dev: device to try to bind to the driver + * +- * First, we call the bus's match function, if one present, which should +- * compare the device IDs the driver supports with the device IDs of the +- * device. Note we don't do this ourselves because we don't know the +- * format of the ID structures, nor what is to be considered a match and +- * what is not. +- * +- * This function returns 1 if a match is found, -ENODEV if the device is +- * not registered, and 0 otherwise. ++ * This function returns -ENODEV if the device is not registered, ++ * 1 if the device is bound sucessfully and 0 otherwise. + * + * This function must be called with @dev->sem held. When called for a + * USB interface, @dev->parent->sem must be held as well. +@@ -190,21 +184,22 @@ int driver_probe_device(struct device_dr + + if (!device_is_registered(dev)) + return -ENODEV; +- if (drv->bus->match && !drv->bus->match(dev, drv)) +- goto done; + + pr_debug("bus: '%s': %s: matched device %s with driver %s\n", + drv->bus->name, __func__, dev_name(dev), drv->name); + + ret = really_probe(dev, drv); + +-done: + return ret; + } + + static int __device_attach(struct device_driver *drv, void *data) + { + struct device *dev = data; ++ ++ if (!driver_match_device(drv, dev)) ++ return 0; ++ + return driver_probe_device(drv, dev); + } + +@@ -257,7 +252,7 @@ static int __driver_attach(struct device + * is an error. + */ + +- if (drv->bus->match && !drv->bus->match(dev, drv)) ++ if (!driver_match_device(drv, dev)) + return 0; + + if (dev->parent) /* Needed for USB */ diff --git a/driver-core/sysfs-take-sysfs_mutex-when-fetching-the-root-inode.patch b/driver-core/sysfs-take-sysfs_mutex-when-fetching-the-root-inode.patch new file mode 100644 index 00000000000000..9f6a10ce4be843 --- /dev/null +++ b/driver-core/sysfs-take-sysfs_mutex-when-fetching-the-root-inode.patch @@ -0,0 +1,36 @@ +From ebiederm@xmission.com Sun Jan 25 15:25:49 2009 +From: ebiederm@xmission.com (Eric W. Biederman) +Date: Wed, 21 Jan 2009 11:55:11 -0800 +Subject: sysfs: Take sysfs_mutex when fetching the root inode. +To: Greg Kroah-Hartman <gregkh@suse.de> +Cc: <linux-kernel@vger.kernel.org>, Al Viro <viro@ZenIV.linux.org.uk>, Tejun Heo <tj@kernel.org>, Cornelia Huck <cornelia.huck@de.ibm.com>, Andrew Morton <akpm@linux-foundation.org> +Message-ID: <m13afch1sw.fsf@fess.ebiederm.org> + + +sysfs_get_inode ultimately calls sysfs_count_nlink when the a +directory inode is fectched. sysfs_count_nlink needs to be +called under the sysfs_mutex to guard against the unlikely +but possible scenario that the root directory is changing +as we are counting the number entries in it, and just in +general to be consistent. + +Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com> +Acked-by: Tejun Heo <tj@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + fs/sysfs/mount.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/sysfs/mount.c ++++ b/fs/sysfs/mount.c +@@ -52,7 +52,9 @@ static int sysfs_fill_super(struct super + sysfs_sb = sb; + + /* get root inode, initialize and unlock it */ ++ mutex_lock(&sysfs_mutex); + inode = sysfs_get_inode(&sysfs_root); ++ mutex_unlock(&sysfs_mutex); + if (!inode) { + pr_debug("sysfs: could not get root inode\n"); + return -ENOMEM; diff --git a/driver-core/sysfs-use-standard-magic.h-for-sysfs.patch b/driver-core/sysfs-use-standard-magic.h-for-sysfs.patch new file mode 100644 index 00000000000000..9763c9c6ea62a6 --- /dev/null +++ b/driver-core/sysfs-use-standard-magic.h-for-sysfs.patch @@ -0,0 +1,34 @@ +From qhfeng.kernel@gmail.com Sun Jan 25 15:12:18 2009 +From: Qinghuang Feng <qhfeng.kernel@gmail.com> +Date: Wed, 14 Jan 2009 15:45:13 +0800 +Subject: SYSFS: use standard magic.h for sysfs +To: gregkh@suse.de +Cc: linux-kernel@vger.kernel.org +Message-ID: <496d980e.160d6e0a.14d0.ffffbe3d@mx.google.com> + + +SYSFS_MAGIC has been added into magic.h, so only use that definition +in magic.h to avoid potential consistency problem. + +Signed-off-by: Qinghuang Feng <qhfeng.kernel@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + fs/sysfs/mount.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/fs/sysfs/mount.c ++++ b/fs/sysfs/mount.c +@@ -17,11 +17,10 @@ + #include <linux/pagemap.h> + #include <linux/init.h> + #include <linux/module.h> ++#include <linux/magic.h> + + #include "sysfs.h" + +-/* Random magic number */ +-#define SYSFS_MAGIC 0x62656572 + + static struct vfsmount *sysfs_mount; + struct super_block * sysfs_sb = NULL; @@ -18,6 +18,7 @@ driver-core.current/debugfs-introduce-stub-for-debugfs_create_size_t-when-debug_ driver-core.current/klist.c-bit-0-in-pointer-can-t-be-used-as-flag.patch driver-core.current/sync-patch-for-jp_jp-stable_kernel_rules.txt.patch driver-core.current/uio-add-missing-documentation-of-features-added-recently.patch +driver-core.current/driver-core-fix-kernel-doc-parameter-name.patch ################################# # USB patches for 2.6.29 @@ -51,6 +52,12 @@ usb.current/usb-usbmon-implement-compat_ioctl.patch usb.current/usb-storage-support-of-dane-elec-mediatouch-usb-device.patch usb.current/usb-remove-zte-modem-from-unusual_devices.patch usb.current/usb-option-driver-onda-device-mt503hs-has-wrong-id.patch +usb.current/usb-cdc-acm-add-another-conexant-modem-to-the-quirks.patch +usb.current/usb-new-id-for-ti_usb_3410_5052-driver.patch +usb.current/usb-gadget-fix-x-y.patch +usb.current/usb-unusual_dev-usb-storage-needs-to-ignore-a-device.patch +usb.current/usb-storage-add-another-unusual_dev-for-off-by-one-bug.patch +usb.current/usb-option-add-quanta-hsdpa-data-card-device-ids.patch usb.current/usb-driver-for-freescale-quicc-engine-usb-host-controller.patch @@ -100,6 +107,9 @@ driver-core/bus_id-wimax.patch driver-core/bus_id-usb.patch driver-core/driver-core-get-rid-of-struct-device-s-bus_id-string-array.patch +driver-core/sysfs-use-standard-magic.h-for-sysfs.patch +driver-core/sysfs-take-sysfs_mutex-when-fetching-the-root-inode.patch +driver-core/driver-core-check-bus-match-without-holding-device-lock.patch driver-core/uio-add-name-attributes-for-mappings-and-port-regions.patch # helper tools, not for mainline. @@ -119,7 +129,11 @@ usb/usb-ub-use-usb-api-functions-rather-than-constants.patch usb/usb-remove-redundant-test-in-pxa27x_udc-and-ftdi_sio.patch usb/usb-drivers-use-usb-api-functions-rather-than-constants.patch usb/usb-gadget-remove-duplicated-include.patch - +usb/usb-usb-serial-ch341-support-for-dtr-rts-cts.patch +usb/usb-imx_udc-fix-imx-udc-gadget-bugs.patch +usb/usb-imx_udc-fix-imx-udc-gadget-code-style.patch +usb/usb-imx_udc-fix-imx-udc-gadget-ep0-irq-handling.patch +usb/usb-imx_udc-fix-imx-udc-gadget-general-irq-handling.patch # stuff I want in my tree, but not to go into -next gregkh.post/usb-gotemp.patch diff --git a/usb.current/usb-cdc-acm-add-another-conexant-modem-to-the-quirks.patch b/usb.current/usb-cdc-acm-add-another-conexant-modem-to-the-quirks.patch new file mode 100644 index 00000000000000..630f3ef04298bd --- /dev/null +++ b/usb.current/usb-cdc-acm-add-another-conexant-modem-to-the-quirks.patch @@ -0,0 +1,32 @@ +From alan@lxorguk.ukuu.org.uk Sun Jan 25 15:09:07 2009 +From: Alan Cox <alan@lxorguk.ukuu.org.uk> +Date: Sun, 11 Jan 2009 19:53:10 +0000 +Subject: USB: cdc-acm: Add another conexant modem to the quirks +To: greg@kroah.com, linux-usb@vger.kernel.org +Message-ID: <20090111195252.16388.74534.stgit@localhost.localdomain> + + +From: Alan Cox <alan@redhat.com> + +Another Conexant, another device with the same quirk + +Signed-off-by: Alan Cox <alan@redhat.com> +Acked-by: Oliver Neukum <oliver@neukum.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/class/cdc-acm.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -1376,6 +1376,9 @@ static struct usb_device_id acm_ids[] = + { USB_DEVICE(0x0572, 0x1321), /* Conexant USB MODEM CX93010 */ + .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ + }, ++ { USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */ ++ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ ++ }, + + /* control interfaces with various AT-command sets */ + { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, diff --git a/usb.current/usb-gadget-fix-x-y.patch b/usb.current/usb-gadget-fix-x-y.patch new file mode 100644 index 00000000000000..52688d5b9b03a3 --- /dev/null +++ b/usb.current/usb-gadget-fix-x-y.patch @@ -0,0 +1,30 @@ +From roel.kluin@gmail.com Sun Jan 25 15:20:37 2009 +From: Roel Kluin <roel.kluin@gmail.com> +Date: Sat, 17 Jan 2009 16:52:17 +0100 +Subject: USB: GADGET: fix !x & y +To: augulis.darius@gmail.com, Greg KH <gregkh@suse.de>, dbrownell@users.sourceforge.net +Cc: linux-usb@vger.kernel.org +Message-ID: <4971FEB1.2000000@gmail.com> + + +! has a higher precedence than & + +Signed-off-by: Roel Kluin <roel.kluin@gmail.com> +Acked-by: David Brownell <dbrownell@users.sourceforge.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/gadget/imx_udc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/gadget/imx_udc.c ++++ b/drivers/usb/gadget/imx_udc.c +@@ -297,7 +297,7 @@ void imx_ep_stall(struct imx_ep_struct * + + for (i = 0; i < 100; i ++) { + temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); +- if (!temp & EPSTAT_STALL) ++ if (!(temp & EPSTAT_STALL)) + break; + udelay(20); + } diff --git a/usb.current/usb-new-id-for-ti_usb_3410_5052-driver.patch b/usb.current/usb-new-id-for-ti_usb_3410_5052-driver.patch new file mode 100644 index 00000000000000..882c8765fe012b --- /dev/null +++ b/usb.current/usb-new-id-for-ti_usb_3410_5052-driver.patch @@ -0,0 +1,57 @@ +From oliver@neukum.org Sun Jan 25 15:09:34 2009 +From: Oliver Neukum <oliver@neukum.org> +Date: Mon, 12 Jan 2009 13:31:16 +0100 +Subject: USB: new id for ti_usb_3410_5052 driver +To: "Greg Kroah-Hartman" <gregkh@suse.de>, linux-usb@vger.kernel.org +Message-ID: <200901121331.16871.oliver@neukum.org> +Content-Disposition: inline + + +This adds a new device id + +Signed-off-by: Oliver Neukum <oneukum@suse.de> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/ti_usb_3410_5052.c | 3 +++ + drivers/usb/serial/ti_usb_3410_5052.h | 2 ++ + 2 files changed, 5 insertions(+) + +--- a/drivers/usb/serial/ti_usb_3410_5052.c ++++ b/drivers/usb/serial/ti_usb_3410_5052.c +@@ -184,6 +184,7 @@ static struct usb_device_id ti_id_table_ + { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_PRODUCT_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_PRODUCT_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_EDGE_PRODUCT_ID) }, ++ { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) }, + }; + + static struct usb_device_id ti_id_table_5052[4+TI_EXTRA_VID_PID_COUNT+1] = { +@@ -191,6 +192,7 @@ static struct usb_device_id ti_id_table_ + { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, ++ { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) }, + }; + + static struct usb_device_id ti_id_table_combined[6+2*TI_EXTRA_VID_PID_COUNT+1] = { +@@ -205,6 +207,7 @@ static struct usb_device_id ti_id_table_ + { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, ++ { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) }, + { } + }; + +--- a/drivers/usb/serial/ti_usb_3410_5052.h ++++ b/drivers/usb/serial/ti_usb_3410_5052.h +@@ -27,7 +27,9 @@ + + /* Vendor and product ids */ + #define TI_VENDOR_ID 0x0451 ++#define IBM_VENDOR_ID 0x04b3 + #define TI_3410_PRODUCT_ID 0x3410 ++#define IBM_4543_PRODUCT_ID 0x4543 + #define TI_3410_EZ430_ID 0xF430 /* TI ez430 development tool */ + #define TI_5052_BOOT_PRODUCT_ID 0x5052 /* no EEPROM, no firmware */ + #define TI_5152_BOOT_PRODUCT_ID 0x5152 /* no EEPROM, no firmware */ diff --git a/usb.current/usb-option-add-quanta-hsdpa-data-card-device-ids.patch b/usb.current/usb-option-add-quanta-hsdpa-data-card-device-ids.patch new file mode 100644 index 00000000000000..64b4d8cf70d72a --- /dev/null +++ b/usb.current/usb-option-add-quanta-hsdpa-data-card-device-ids.patch @@ -0,0 +1,48 @@ +From Alex.Cheng@quantatw.com Sun Jan 25 15:26:31 2009 +From: <Alex.Cheng@quantatw.com> +Date: Thu, 22 Jan 2009 16:01:57 +0800 +Subject: USB: option: add QUANTA HSDPA Data Card device ids +To: <smurf@smurf.noris.de> +Cc: <Alex.Cheng@quantatw.com> +Message-ID: <859A00560C629C4FBE3985C4272AE5F504A9D1AD@Mail03.quanta.corp> + + +This patch adds the support for the QUANTA Q101 series HSDPA Data Card. +With the vendor and product IDs are set properly, +the data card can be detected and works fine. + +Signed-off-by: Alex Cheng <alex.cheng@quantatw.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/option.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -158,6 +158,13 @@ static int option_send_setup(struct tty + #define HUAWEI_PRODUCT_E143E 0x143E + #define HUAWEI_PRODUCT_E143F 0x143F + ++#define QUANTA_VENDOR_ID 0x0408 ++#define QUANTA_PRODUCT_Q101 0xEA02 ++#define QUANTA_PRODUCT_Q111 0xEA03 ++#define QUANTA_PRODUCT_GLX 0xEA04 ++#define QUANTA_PRODUCT_GKE 0xEA05 ++#define QUANTA_PRODUCT_GLE 0xEA06 ++ + #define NOVATELWIRELESS_VENDOR_ID 0x1410 + + /* YISO PRODUCTS */ +@@ -298,6 +305,11 @@ static struct usb_device_id option_ids[] + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_GT) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_EX) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_MODEM) }, ++ { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_Q101) }, ++ { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_Q111) }, ++ { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLX) }, ++ { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GKE) }, ++ { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS, 0xff, 0xff, 0xff) }, diff --git a/usb.current/usb-storage-add-another-unusual_dev-for-off-by-one-bug.patch b/usb.current/usb-storage-add-another-unusual_dev-for-off-by-one-bug.patch new file mode 100644 index 00000000000000..35b93b8aed4f89 --- /dev/null +++ b/usb.current/usb-storage-add-another-unusual_dev-for-off-by-one-bug.patch @@ -0,0 +1,38 @@ +From phil@ipom.com Sun Jan 25 15:21:50 2009 +From: Phil Dibowitz <phil@ipom.com> +Date: Tue, 20 Jan 2009 23:42:52 +0100 +Subject: USB: storage: Add another unusual_dev for off-by-one bug +To: Greg KH <greg@kroah.com>, USB Dev <linux-usb@vger.kernel.org>, USB Storage list <usb-storage@lists.one-eyed-alien.net> +Cc: Martijn Hijdra <martijn.hijdra@gmail.com> +Message-ID: <4976536C.1000205@ipom.com> + + +Argosy has released another device with the off-by-one sector. This is a +harddrive with an internal cardreader which is affected. + +Based on a patch written by Martijn Hijdra <martijn.hijdra@gmail.com> + +Signed-off-by: Phil Dibowitz <phil@ipom.com> +Cc: Martijn Hijdra <martijn.hijdra@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/storage/unusual_devs.h | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/usb/storage/unusual_devs.h ++++ b/drivers/usb/storage/unusual_devs.h +@@ -1261,6 +1261,13 @@ UNUSUAL_DEV( 0x0840, 0x0084, 0x0001, 0x0 + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + ++/* Reported by Martijn Hijdra <martijn.hijdra@gmail.com> */ ++UNUSUAL_DEV( 0x0840, 0x0085, 0x0001, 0x0001, ++ "Argosy", ++ "Storage", ++ US_SC_DEVICE, US_PR_DEVICE, NULL, ++ US_FL_FIX_CAPACITY), ++ + /* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>. + * Flag will support Bulk devices which use a standards-violating 32-byte + * Command Block Wrapper. Here, the "DC2MEGA" cameras (several brands) with diff --git a/usb.current/usb-unusual_dev-usb-storage-needs-to-ignore-a-device.patch b/usb.current/usb-unusual_dev-usb-storage-needs-to-ignore-a-device.patch new file mode 100644 index 00000000000000..0b30bb2ce7ef95 --- /dev/null +++ b/usb.current/usb-unusual_dev-usb-storage-needs-to-ignore-a-device.patch @@ -0,0 +1,40 @@ +From phil@ipom.com Sun Jan 25 15:21:21 2009 +From: Phil Dibowitz <phil@ipom.com> +Date: Tue, 20 Jan 2009 23:48:36 +0100 +Subject: USB: unusual_dev: usb-storage needs to ignore a device +To: Greg KH <greg@kroah.com> +Cc: USB Dev <linux-usb@vger.kernel.org>, USB Storage list <usb-storage@lists.one-eyed-alien.net>, The Solutor <thesolutor@gmail.com> +Message-ID: <497654C4.1000200@ipom.com> + +This patch adds an unusual_devs entry for a Sony Ericsson modem. Like many +other modems, we have to ignore the storage device in order to access the +modem. + + +At this time usb_modeswitch does not work with this device. + + +Reported-by: The Solutor <thesolutor@gmail.com>. +Signed-off-by: Phil Dibowitz <phil@ipom.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/storage/unusual_devs.h | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/usb/storage/unusual_devs.h ++++ b/drivers/usb/storage/unusual_devs.h +@@ -1599,6 +1599,13 @@ UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_NO_WP_DETECT ), + ++/* Reported by The Solutor <thesolutor@gmail.com> */ ++UNUSUAL_DEV( 0x0fce, 0xd0e1, 0x0000, 0x0000, ++ "Sony Ericsson", ++ "MD400", ++ US_SC_DEVICE, US_PR_DEVICE, NULL, ++ US_FL_IGNORE_DEVICE), ++ + /* Reported by Jan Mate <mate@fiit.stuba.sk> + * and by Soeren Sonnenburg <kernel@nn7.de> */ + UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000, diff --git a/usb/usb-imx_udc-fix-imx-udc-gadget-bugs.patch b/usb/usb-imx_udc-fix-imx-udc-gadget-bugs.patch new file mode 100644 index 00000000000000..106385543e208f --- /dev/null +++ b/usb/usb-imx_udc-fix-imx-udc-gadget-bugs.patch @@ -0,0 +1,145 @@ +From augulis.darius@gmail.com Sun Jan 25 15:23:01 2009 +From: Darius <augulis.darius@gmail.com> +Date: Wed, 21 Jan 2009 15:17:25 +0200 +Subject: USB: imx_udc: Fix IMX UDC gadget bugs +To: linux-usb@vger.kernel.org +Message-ID: <gl77dh$fum$2@ger.gmane.org> + + +From: Darius Augulis <augulis.darius@gmail.com> + +Fix small bugs and add some omptimization in IMX UDC Gadget. + +Signed-off-by: Darius Augulis <augulis.darius@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/gadget/imx_udc.c | 33 +++++++++++++++++++-------------- + drivers/usb/gadget/imx_udc.h | 2 +- + 2 files changed, 20 insertions(+), 15 deletions(-) + +--- a/drivers/usb/gadget/imx_udc.c ++++ b/drivers/usb/gadget/imx_udc.c +@@ -283,7 +283,7 @@ void imx_ep_stall(struct imx_ep_struct * + imx_flush(imx_ep); + + /* Special care for ep0 */ +- if (EP_NO(imx_ep)) { ++ if (!EP_NO(imx_ep)) { + temp = __raw_readl(imx_usb->base + USB_CTRL); + __raw_writel(temp | CTRL_CMDOVER | CTRL_CMDERROR, imx_usb->base + USB_CTRL); + do { } while (__raw_readl(imx_usb->base + USB_CTRL) & CTRL_CMDOVER); +@@ -301,7 +301,7 @@ void imx_ep_stall(struct imx_ep_struct * + break; + udelay(20); + } +- if (i == 50) ++ if (i == 100) + D_ERR(imx_usb->dev, "<%s> Non finished stall on %s\n", + __func__, imx_ep->ep.name); + } +@@ -539,8 +539,7 @@ static int handle_ep0(struct imx_ep_stru + struct imx_request *req = NULL; + int ret = 0; + +- if (!list_empty(&imx_ep->queue)) +- req = list_entry(imx_ep->queue.next, struct imx_request, queue); ++ req = list_entry(imx_ep->queue.next, struct imx_request, queue); + + if (req) { + switch (imx_ep->imx_usb->ep0state) { +@@ -561,6 +560,10 @@ static int handle_ep0(struct imx_ep_stru + } + } + ++ else ++ D_ERR(imx_ep->imx_usb->dev, "<%s> no request on %s\n", ++ __func__, imx_ep->ep.name); ++ + return ret; + } + +@@ -759,7 +762,7 @@ static int imx_ep_queue + */ + if (imx_usb->set_config && !EP_NO(imx_ep)) { + imx_usb->set_config = 0; +- D_EPX(imx_usb->dev, ++ D_ERR(imx_usb->dev, + "<%s> gadget reply set config\n", __func__); + return 0; + } +@@ -779,8 +782,6 @@ static int imx_ep_queue + return -ESHUTDOWN; + } + +- local_irq_save(flags); +- + /* Debug */ + D_REQ(imx_usb->dev, "<%s> ep%d %s request for [%d] bytes\n", + __func__, EP_NO(imx_ep), +@@ -790,17 +791,18 @@ static int imx_ep_queue + + if (imx_ep->stopped) { + usb_req->status = -ESHUTDOWN; +- ret = -ESHUTDOWN; +- goto out; ++ return -ESHUTDOWN; + } + + if (req->in_use) { + D_ERR(imx_usb->dev, + "<%s> refusing to queue req %p (already queued)\n", + __func__, req); +- goto out; ++ return 0; + } + ++ local_irq_save(flags); ++ + usb_req->status = -EINPROGRESS; + usb_req->actual = 0; + +@@ -810,7 +812,7 @@ static int imx_ep_queue + ret = handle_ep0(imx_ep); + else + ret = handle_ep(imx_ep); +-out: ++ + local_irq_restore(flags); + return ret; + } +@@ -1010,10 +1012,8 @@ static irqreturn_t imx_udc_irq(int irq, + dump_usb_stat(__func__, imx_usb); + } + +- if (!imx_usb->driver) { +- /*imx_udc_disable(imx_usb);*/ ++ if (!imx_usb->driver) + goto end_irq; +- } + + if (intr & INTR_WAKEUP) { + if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN +@@ -1095,6 +1095,11 @@ static irqreturn_t imx_udc_irq(int irq, + } + + if (intr & INTR_SOF) { ++ /* Copy from Motorola BSP. ++ We must enable SOF intr and set CMDOVER. ++ Datasheet don't specifiy this action, but it ++ is done in Motorola BSP, so just copy it. ++ */ + if (imx_usb->ep0state == EP0_IDLE) { + temp = __raw_readl(imx_usb->base + USB_CTRL); + __raw_writel(temp | CTRL_CMDOVER, imx_usb->base + USB_CTRL); +--- a/drivers/usb/gadget/imx_udc.h ++++ b/drivers/usb/gadget/imx_udc.h +@@ -170,7 +170,7 @@ struct imx_udc_struct { + /* #define DEBUG_IRQ */ + /* #define DEBUG_EPIRQ */ + /* #define DEBUG_DUMP */ +-#define DEBUG_ERR ++/* #define DEBUG_ERR */ + + #ifdef DEBUG_REQ + #define D_REQ(dev, args...) dev_dbg(dev, ## args) diff --git a/usb/usb-imx_udc-fix-imx-udc-gadget-code-style.patch b/usb/usb-imx_udc-fix-imx-udc-gadget-code-style.patch new file mode 100644 index 00000000000000..f0eab8fc30f8c5 --- /dev/null +++ b/usb/usb-imx_udc-fix-imx-udc-gadget-code-style.patch @@ -0,0 +1,319 @@ +From augulis.darius@gmail.com Sun Jan 25 15:24:22 2009 +From: Darius <augulis.darius@gmail.com> +Date: Wed, 21 Jan 2009 15:17:55 +0200 +Subject: USB: imx_udc: Fix IMX UDC gadget code style +To: linux-usb@vger.kernel.org +Message-ID: <gl77ef$fum$3@ger.gmane.org> + + +From: Darius Augulis <augulis.darius@gmail.com> + +Fix code style errors in IMX UDC Gadget. + +Signed-off-by: Darius Augulis <augulis.darius@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/gadget/imx_udc.c | 59 ++++++++++++++++++++++++++++--------------- + drivers/usb/gadget/imx_udc.h | 46 +++++++++++++++++++++------------ + 2 files changed, 69 insertions(+), 36 deletions(-) + +--- a/drivers/usb/gadget/imx_udc.c ++++ b/drivers/usb/gadget/imx_udc.c +@@ -1,7 +1,7 @@ + /* + * driver/usb/gadget/imx_udc.c + * +- * Copyright (C) 2005 Mike Lee(eemike@gmail.com) ++ * Copyright (C) 2005 Mike Lee <eemike@gmail.com> + * Copyright (C) 2008 Darius Augulis <augulis.darius@gmail.com> + * + * This program is free software; you can redistribute it and/or modify +@@ -51,7 +51,8 @@ void ep0_chg_stat(const char *label, str + void imx_udc_enable(struct imx_udc_struct *imx_usb) + { + int temp = __raw_readl(imx_usb->base + USB_CTRL); +- __raw_writel(temp | CTRL_FE_ENA | CTRL_AFE_ENA, imx_usb->base + USB_CTRL); ++ __raw_writel(temp | CTRL_FE_ENA | CTRL_AFE_ENA, ++ imx_usb->base + USB_CTRL); + imx_usb->gadget.speed = USB_SPEED_FULL; + } + +@@ -126,7 +127,8 @@ void imx_udc_config(struct imx_udc_struc + for (j = 0; j < 5; j++) { + __raw_writeb(ep_conf[j], + imx_usb->base + USB_DDAT); +- do {} while (__raw_readl(imx_usb->base + USB_DADR) ++ do {} while (__raw_readl(imx_usb->base ++ + USB_DADR) + & DADR_BSY); + } + } +@@ -183,7 +185,8 @@ void imx_udc_init_ep(struct imx_udc_stru + temp = (EP_DIR(imx_ep) << 7) | (max << 5) + | (imx_ep->bmAttributes << 3); + __raw_writel(temp, imx_usb->base + USB_EP_STAT(i)); +- __raw_writel(temp | EPSTAT_FLUSH, imx_usb->base + USB_EP_STAT(i)); ++ __raw_writel(temp | EPSTAT_FLUSH, ++ imx_usb->base + USB_EP_STAT(i)); + D_INI(imx_usb->dev, "<%s> ep%d_stat %08x\n", __func__, i, + __raw_readl(imx_usb->base + USB_EP_STAT(i))); + } +@@ -278,15 +281,18 @@ void imx_ep_stall(struct imx_ep_struct * + struct imx_udc_struct *imx_usb = imx_ep->imx_usb; + int temp, i; + +- D_ERR(imx_usb->dev, "<%s> Forced stall on %s\n", __func__, imx_ep->ep.name); ++ D_ERR(imx_usb->dev, ++ "<%s> Forced stall on %s\n", __func__, imx_ep->ep.name); + + imx_flush(imx_ep); + + /* Special care for ep0 */ + if (!EP_NO(imx_ep)) { + temp = __raw_readl(imx_usb->base + USB_CTRL); +- __raw_writel(temp | CTRL_CMDOVER | CTRL_CMDERROR, imx_usb->base + USB_CTRL); +- do { } while (__raw_readl(imx_usb->base + USB_CTRL) & CTRL_CMDOVER); ++ __raw_writel(temp | CTRL_CMDOVER | CTRL_CMDERROR, ++ imx_usb->base + USB_CTRL); ++ do { } while (__raw_readl(imx_usb->base + USB_CTRL) ++ & CTRL_CMDOVER); + temp = __raw_readl(imx_usb->base + USB_CTRL); + __raw_writel(temp & ~CTRL_CMDERROR, imx_usb->base + USB_CTRL); + } +@@ -296,7 +302,8 @@ void imx_ep_stall(struct imx_ep_struct * + imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); + + for (i = 0; i < 100; i ++) { +- temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); ++ temp = __raw_readl(imx_usb->base ++ + USB_EP_STAT(EP_NO(imx_ep))); + if (!(temp & EPSTAT_STALL)) + break; + udelay(20); +@@ -325,7 +332,8 @@ static int imx_udc_wakeup(struct usb_gad + ******************************************************************************* + */ + +-static void ep_add_request(struct imx_ep_struct *imx_ep, struct imx_request *req) ++static void ep_add_request(struct imx_ep_struct *imx_ep, ++ struct imx_request *req) + { + if (unlikely(!req)) + return; +@@ -334,7 +342,8 @@ static void ep_add_request(struct imx_ep + list_add_tail(&req->queue, &imx_ep->queue); + } + +-static void ep_del_request(struct imx_ep_struct *imx_ep, struct imx_request *req) ++static void ep_del_request(struct imx_ep_struct *imx_ep, ++ struct imx_request *req) + { + if (unlikely(!req)) + return; +@@ -343,7 +352,8 @@ static void ep_del_request(struct imx_ep + req->in_use = 0; + } + +-static void done(struct imx_ep_struct *imx_ep, struct imx_request *req, int status) ++static void done(struct imx_ep_struct *imx_ep, ++ struct imx_request *req, int status) + { + ep_del_request(imx_ep, req); + +@@ -494,7 +504,8 @@ static int write_fifo(struct imx_ep_stru + __func__, imx_ep->ep.name, req, + completed ? "completed" : "not completed"); + if (!EP_NO(imx_ep)) +- ep0_chg_stat(__func__, imx_ep->imx_usb, EP0_IDLE); ++ ep0_chg_stat(__func__, ++ imx_ep->imx_usb, EP0_IDLE); + } + } + +@@ -586,7 +597,8 @@ static void handle_ep0_devreq(struct imx + "<%s> no setup packet received\n", __func__); + goto stall; + } +- u.word[i] = __raw_readl(imx_usb->base + USB_EP_FDAT(EP_NO(imx_ep))); ++ u.word[i] = __raw_readl(imx_usb->base ++ + USB_EP_FDAT(EP_NO(imx_ep))); + } + + temp = imx_ep_empty(imx_ep); +@@ -785,8 +797,10 @@ static int imx_ep_queue + /* Debug */ + D_REQ(imx_usb->dev, "<%s> ep%d %s request for [%d] bytes\n", + __func__, EP_NO(imx_ep), +- ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state == EP0_IN_DATA_PHASE) +- || (EP_NO(imx_ep) && EP_DIR(imx_ep))) ? "IN" : "OUT", usb_req->length); ++ ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state ++ == EP0_IN_DATA_PHASE) ++ || (EP_NO(imx_ep) && EP_DIR(imx_ep))) ++ ? "IN" : "OUT", usb_req->length); + dump_req(__func__, imx_ep, usb_req); + + if (imx_ep->stopped) { +@@ -1061,7 +1075,8 @@ static irqreturn_t imx_udc_irq(int irq, + + /* Config setup */ + if (imx_usb->cfg != cfg) { +- D_REQ(imx_usb->dev, "<%s> Change config start\n",__func__); ++ D_REQ(imx_usb->dev, ++ "<%s> Change config start\n", __func__); + u.bRequest = USB_REQ_SET_CONFIGURATION; + u.bRequestType = USB_DIR_OUT | + USB_TYPE_STANDARD | +@@ -1073,11 +1088,13 @@ static irqreturn_t imx_udc_irq(int irq, + imx_usb->set_config = 1; + imx_usb->driver->setup(&imx_usb->gadget, &u); + imx_usb->set_config = 0; +- D_REQ(imx_usb->dev, "<%s> Change config done\n",__func__); ++ D_REQ(imx_usb->dev, ++ "<%s> Change config done\n", __func__); + + } + if (imx_usb->intf != intf || imx_usb->alt != alt) { +- D_REQ(imx_usb->dev, "<%s> Change interface start\n",__func__); ++ D_REQ(imx_usb->dev, ++ "<%s> Change interface start\n", __func__); + u.bRequest = USB_REQ_SET_INTERFACE; + u.bRequestType = USB_DIR_OUT | + USB_TYPE_STANDARD | +@@ -1090,7 +1107,8 @@ static irqreturn_t imx_udc_irq(int irq, + imx_usb->set_config = 1; + imx_usb->driver->setup(&imx_usb->gadget, &u); + imx_usb->set_config = 0; +- D_REQ(imx_usb->dev, "<%s> Change interface done\n",__func__); ++ D_REQ(imx_usb->dev, ++ "<%s> Change interface done\n", __func__); + } + } + +@@ -1102,7 +1120,8 @@ static irqreturn_t imx_udc_irq(int irq, + */ + if (imx_usb->ep0state == EP0_IDLE) { + temp = __raw_readl(imx_usb->base + USB_CTRL); +- __raw_writel(temp | CTRL_CMDOVER, imx_usb->base + USB_CTRL); ++ __raw_writel(temp | CTRL_CMDOVER, ++ imx_usb->base + USB_CTRL); + } + } + +--- a/drivers/usb/gadget/imx_udc.h ++++ b/drivers/usb/gadget/imx_udc.h +@@ -23,7 +23,8 @@ + /* Helper macros */ + #define EP_NO(ep) ((ep->bEndpointAddress) & ~USB_DIR_IN) /* IN:1, OUT:0 */ + #define EP_DIR(ep) ((ep->bEndpointAddress) & USB_DIR_IN ? 1 : 0) +-#define irq_to_ep(irq) (((irq) >= USBD_INT0) || ((irq) <= USBD_INT6) ? ((irq) - USBD_INT0) : (USBD_INT6)) /*should not happen*/ ++#define irq_to_ep(irq) (((irq) >= USBD_INT0) || ((irq) <= USBD_INT6) \ ++ ? ((irq) - USBD_INT0) : (USBD_INT6)) /*should not happen*/ + #define ep_to_irq(ep) (EP_NO((ep)) + USBD_INT0) + #define IMX_USB_NB_EP 6 + +@@ -88,8 +89,8 @@ struct imx_udc_struct { + #define USB_EP_FDAT3(x) (0x3F + (x*0x30)) /* USB FIFO data */ + #define USB_EP_FSTAT(x) (0x40 + (x*0x30)) /* USB FIFO status */ + #define USB_EP_FCTRL(x) (0x44 + (x*0x30)) /* USB FIFO control */ +-#define USB_EP_LRFP(x) (0x48 + (x*0x30)) /* USB last read frame pointer */ +-#define USB_EP_LWFP(x) (0x4C + (x*0x30)) /* USB last write frame pointer */ ++#define USB_EP_LRFP(x) (0x48 + (x*0x30)) /* USB last rd f. pointer */ ++#define USB_EP_LWFP(x) (0x4C + (x*0x30)) /* USB last wr f. pointer */ + #define USB_EP_FALRM(x) (0x50 + (x*0x30)) /* USB FIFO alarm */ + #define USB_EP_FRDP(x) (0x54 + (x*0x30)) /* USB FIFO read pointer */ + #define USB_EP_FWRP(x) (0x58 + (x*0x30)) /* USB FIFO write pointer */ +@@ -228,7 +229,8 @@ struct imx_udc_struct { + #endif /* DEBUG_IRQ */ + + #ifdef DEBUG_EPIRQ +- static void dump_ep_intr(const char *label, int nr, int irqreg, struct device *dev) ++ static void dump_ep_intr(const char *label, int nr, int irqreg, ++ struct device *dev) + { + dev_dbg(dev, "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n", label, nr, + (irqreg & EPINTR_FIFO_FULL) ? " full" : "", +@@ -246,7 +248,8 @@ struct imx_udc_struct { + #endif /* DEBUG_IRQ */ + + #ifdef DEBUG_DUMP +- static void dump_usb_stat(const char *label, struct imx_udc_struct *imx_usb) ++ static void dump_usb_stat(const char *label, ++ struct imx_udc_struct *imx_usb) + { + int temp = __raw_readl(imx_usb->base + USB_STAT); + +@@ -259,12 +262,15 @@ struct imx_udc_struct { + (temp & STAT_ALTSET)); + } + +- static void dump_ep_stat(const char *label, struct imx_ep_struct *imx_ep) ++ static void dump_ep_stat(const char *label, ++ struct imx_ep_struct *imx_ep) + { +- int temp = __raw_readl(imx_ep->imx_usb->base + USB_EP_INTR(EP_NO(imx_ep))); ++ int temp = __raw_readl(imx_ep->imx_usb->base ++ + USB_EP_INTR(EP_NO(imx_ep))); + + dev_dbg(imx_ep->imx_usb->dev, +- "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n", label, EP_NO(imx_ep), ++ "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n", ++ label, EP_NO(imx_ep), + (temp & EPINTR_FIFO_FULL) ? " full" : "", + (temp & EPINTR_FIFO_EMPTY) ? " fempty" : "", + (temp & EPINTR_FIFO_ERROR) ? " ferr" : "", +@@ -275,18 +281,22 @@ struct imx_udc_struct { + (temp & EPINTR_DEVREQ) ? " devreq" : "", + (temp & EPINTR_EOT) ? " eot" : ""); + +- temp = __raw_readl(imx_ep->imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); ++ temp = __raw_readl(imx_ep->imx_usb->base ++ + USB_EP_STAT(EP_NO(imx_ep))); + + dev_dbg(imx_ep->imx_usb->dev, +- "<%s> EP%d_STAT=[%s%s bcount=%d]\n", label, EP_NO(imx_ep), ++ "<%s> EP%d_STAT=[%s%s bcount=%d]\n", ++ label, EP_NO(imx_ep), + (temp & EPSTAT_SIP) ? " sip" : "", + (temp & EPSTAT_STALL) ? " stall" : "", + (temp & EPSTAT_BCOUNT) >> 16); + +- temp = __raw_readl(imx_ep->imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep))); ++ temp = __raw_readl(imx_ep->imx_usb->base ++ + USB_EP_FSTAT(EP_NO(imx_ep))); + + dev_dbg(imx_ep->imx_usb->dev, +- "<%s> EP%d_FSTAT=[%s%s%s%s%s%s%s]\n", label, EP_NO(imx_ep), ++ "<%s> EP%d_FSTAT=[%s%s%s%s%s%s%s]\n", ++ label, EP_NO(imx_ep), + (temp & FSTAT_ERR) ? " ferr" : "", + (temp & FSTAT_UF) ? " funder" : "", + (temp & FSTAT_OF) ? " fover" : "", +@@ -296,19 +306,23 @@ struct imx_udc_struct { + (temp & FSTAT_EMPTY) ? " fempty" : ""); + } + +- static void dump_req(const char *label, struct imx_ep_struct *imx_ep, struct usb_request *req) ++ static void dump_req(const char *label, struct imx_ep_struct *imx_ep, ++ struct usb_request *req) + { + int i; + + if (!req || !req->buf) { +- dev_dbg(imx_ep->imx_usb->dev, "<%s> req or req buf is free\n", label); ++ dev_dbg(imx_ep->imx_usb->dev, ++ "<%s> req or req buf is free\n", label); + return; + } + +- if ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state == EP0_IN_DATA_PHASE) ++ if ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state ++ == EP0_IN_DATA_PHASE) + || (EP_NO(imx_ep) && EP_DIR(imx_ep))) { + +- dev_dbg(imx_ep->imx_usb->dev, "<%s> request dump <", label); ++ dev_dbg(imx_ep->imx_usb->dev, ++ "<%s> request dump <", label); + for (i = 0; i < req->length; i++) + printk("%02x-", *((u8 *)req->buf + i)); + printk(">\n"); diff --git a/usb/usb-imx_udc-fix-imx-udc-gadget-ep0-irq-handling.patch b/usb/usb-imx_udc-fix-imx-udc-gadget-ep0-irq-handling.patch new file mode 100644 index 00000000000000..d94bb99f3d0dce --- /dev/null +++ b/usb/usb-imx_udc-fix-imx-udc-gadget-ep0-irq-handling.patch @@ -0,0 +1,51 @@ +From augulis.darius@gmail.com Sun Jan 25 15:24:39 2009 +From: Darius <augulis.darius@gmail.com> +Date: Wed, 21 Jan 2009 15:18:33 +0200 +Subject: USB: imx_udc: Fix IMX UDC gadget ep0 irq handling +To: linux-usb@vger.kernel.org +Message-ID: <gl77fl$fum$4@ger.gmane.org> + + +From: Darius Augulis <augulis.darius@gmail.com> + +Fix ep0 interrupt handling in IMX UDC Gadget. + +Signed-off-by: Darius Augulis <augulis.darius@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/gadget/imx_udc.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/usb/gadget/imx_udc.c ++++ b/drivers/usb/gadget/imx_udc.c +@@ -1133,6 +1133,7 @@ end_irq: + static irqreturn_t imx_udc_ctrl_irq(int irq, void *dev) + { + struct imx_udc_struct *imx_usb = dev; ++ struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[0]; + int intr = __raw_readl(imx_usb->base + USB_EP_INTR(0)); + + dump_ep_intr(__func__, 0, intr, imx_usb->dev); +@@ -1142,16 +1143,15 @@ static irqreturn_t imx_udc_ctrl_irq(int + return IRQ_HANDLED; + } + +- /* DEVREQ IRQ has highest priority */ ++ /* DEVREQ has highest priority */ + if (intr & (EPINTR_DEVREQ | EPINTR_MDEVREQ)) + handle_ep0_devreq(imx_usb); + /* Seem i.MX is missing EOF interrupt sometimes. +- * Therefore we monitor both EOF and FIFO_EMPTY interrups +- * when transmiting, and both EOF and FIFO_FULL when +- * receiving data. ++ * Therefore we don't monitor EOF. ++ * We call handle_ep0() only if a request is queued for ep0. + */ +- else if (intr & (EPINTR_EOF | EPINTR_FIFO_EMPTY | EPINTR_FIFO_FULL)) +- handle_ep0(&imx_usb->imx_ep[0]); ++ else if (!list_empty(&imx_ep->queue)) ++ handle_ep0(imx_ep); + + __raw_writel(intr, imx_usb->base + USB_EP_INTR(0)); + diff --git a/usb/usb-imx_udc-fix-imx-udc-gadget-general-irq-handling.patch b/usb/usb-imx_udc-fix-imx-udc-gadget-general-irq-handling.patch new file mode 100644 index 00000000000000..001514ea725e8c --- /dev/null +++ b/usb/usb-imx_udc-fix-imx-udc-gadget-general-irq-handling.patch @@ -0,0 +1,266 @@ +From augulis.darius@gmail.com Sun Jan 25 15:24:56 2009 +From: Darius <augulis.darius@gmail.com> +Date: Wed, 21 Jan 2009 15:19:19 +0200 +Subject: USB: imx_udc: Fix IMX UDC gadget general irq handling +To: linux-usb@vger.kernel.org +Message-ID: <gl77h3$fum$5@ger.gmane.org> + + +From: Darius Augulis <augulis.darius@gmail.com> + +Workaround of hw bug in IMX UDC. +This bug causes wrong handling of CFG_CHG interrupt. +Workaround is documented inline source code. + +Signed-off-by: Darius Augulis <augulis.darius@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/gadget/imx_udc.c | 160 +++++++++++++++++++++++++------------------ + drivers/usb/gadget/imx_udc.h | 1 + 2 files changed, 95 insertions(+), 66 deletions(-) + +--- a/drivers/usb/gadget/imx_udc.c ++++ b/drivers/usb/gadget/imx_udc.c +@@ -28,6 +28,7 @@ + #include <linux/dma-mapping.h> + #include <linux/clk.h> + #include <linux/delay.h> ++#include <linux/timer.h> + + #include <linux/usb/ch9.h> + #include <linux/usb/gadget.h> +@@ -1013,70 +1014,32 @@ static void udc_stop_activity(struct imx + ******************************************************************************* + */ + +-static irqreturn_t imx_udc_irq(int irq, void *dev) ++/* ++ * Called when timer expires. ++ * Timer is started when CFG_CHG is received. ++ */ ++static void handle_config(unsigned long data) + { +- struct imx_udc_struct *imx_usb = dev; ++ struct imx_udc_struct *imx_usb = (void *)data; + struct usb_ctrlrequest u; + int temp, cfg, intf, alt; +- int intr = __raw_readl(imx_usb->base + USB_INTR); +- +- if (intr & (INTR_WAKEUP | INTR_SUSPEND | INTR_RESUME | INTR_RESET_START +- | INTR_RESET_STOP | INTR_CFG_CHG)) { +- dump_intr(__func__, intr, imx_usb->dev); +- dump_usb_stat(__func__, imx_usb); +- } +- +- if (!imx_usb->driver) +- goto end_irq; +- +- if (intr & INTR_WAKEUP) { +- if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN +- && imx_usb->driver && imx_usb->driver->resume) +- imx_usb->driver->resume(&imx_usb->gadget); +- imx_usb->set_config = 0; +- imx_usb->gadget.speed = USB_SPEED_FULL; +- } +- +- if (intr & INTR_SUSPEND) { +- if (imx_usb->gadget.speed != USB_SPEED_UNKNOWN +- && imx_usb->driver && imx_usb->driver->suspend) +- imx_usb->driver->suspend(&imx_usb->gadget); +- imx_usb->set_config = 0; +- imx_usb->gadget.speed = USB_SPEED_UNKNOWN; +- } + +- if (intr & INTR_RESET_START) { +- __raw_writel(intr, imx_usb->base + USB_INTR); +- udc_stop_activity(imx_usb, imx_usb->driver); +- imx_usb->set_config = 0; +- imx_usb->gadget.speed = USB_SPEED_UNKNOWN; +- } ++ local_irq_disable(); + +- if (intr & INTR_RESET_STOP) +- imx_usb->gadget.speed = USB_SPEED_FULL; +- +- if (intr & INTR_CFG_CHG) { +- __raw_writel(INTR_CFG_CHG, imx_usb->base + USB_INTR); +- temp = __raw_readl(imx_usb->base + USB_STAT); +- cfg = (temp & STAT_CFG) >> 5; +- intf = (temp & STAT_INTF) >> 3; +- alt = temp & STAT_ALTSET; +- +- D_REQ(imx_usb->dev, +- "<%s> orig config C=%d, I=%d, A=%d / " +- "req config C=%d, I=%d, A=%d\n", +- __func__, imx_usb->cfg, imx_usb->intf, imx_usb->alt, +- cfg, intf, alt); ++ temp = __raw_readl(imx_usb->base + USB_STAT); ++ cfg = (temp & STAT_CFG) >> 5; ++ intf = (temp & STAT_INTF) >> 3; ++ alt = temp & STAT_ALTSET; ++ ++ D_REQ(imx_usb->dev, ++ "<%s> orig config C=%d, I=%d, A=%d / " ++ "req config C=%d, I=%d, A=%d\n", ++ __func__, imx_usb->cfg, imx_usb->intf, imx_usb->alt, ++ cfg, intf, alt); + +- if (cfg != 1 && cfg != 2) +- goto end_irq; ++ if (cfg == 1 || cfg == 2) { + +- imx_usb->set_config = 0; +- +- /* Config setup */ + if (imx_usb->cfg != cfg) { +- D_REQ(imx_usb->dev, +- "<%s> Change config start\n", __func__); + u.bRequest = USB_REQ_SET_CONFIGURATION; + u.bRequestType = USB_DIR_OUT | + USB_TYPE_STANDARD | +@@ -1085,16 +1048,10 @@ static irqreturn_t imx_udc_irq(int irq, + u.wIndex = 0; + u.wLength = 0; + imx_usb->cfg = cfg; +- imx_usb->set_config = 1; + imx_usb->driver->setup(&imx_usb->gadget, &u); +- imx_usb->set_config = 0; +- D_REQ(imx_usb->dev, +- "<%s> Change config done\n", __func__); + + } + if (imx_usb->intf != intf || imx_usb->alt != alt) { +- D_REQ(imx_usb->dev, +- "<%s> Change interface start\n", __func__); + u.bRequest = USB_REQ_SET_INTERFACE; + u.bRequestType = USB_DIR_OUT | + USB_TYPE_STANDARD | +@@ -1104,14 +1061,30 @@ static irqreturn_t imx_udc_irq(int irq, + u.wLength = 0; + imx_usb->intf = intf; + imx_usb->alt = alt; +- imx_usb->set_config = 1; + imx_usb->driver->setup(&imx_usb->gadget, &u); +- imx_usb->set_config = 0; +- D_REQ(imx_usb->dev, +- "<%s> Change interface done\n", __func__); + } + } + ++ imx_usb->set_config = 0; ++ ++ local_irq_enable(); ++} ++ ++static irqreturn_t imx_udc_irq(int irq, void *dev) ++{ ++ struct imx_udc_struct *imx_usb = dev; ++ int intr = __raw_readl(imx_usb->base + USB_INTR); ++ int temp; ++ ++ if (intr & (INTR_WAKEUP | INTR_SUSPEND | INTR_RESUME | INTR_RESET_START ++ | INTR_RESET_STOP | INTR_CFG_CHG)) { ++ dump_intr(__func__, intr, imx_usb->dev); ++ dump_usb_stat(__func__, imx_usb); ++ } ++ ++ if (!imx_usb->driver) ++ goto end_irq; ++ + if (intr & INTR_SOF) { + /* Copy from Motorola BSP. + We must enable SOF intr and set CMDOVER. +@@ -1125,6 +1098,55 @@ static irqreturn_t imx_udc_irq(int irq, + } + } + ++ if (intr & INTR_CFG_CHG) { ++ /* A workaround of serious IMX UDC bug. ++ Handling of CFG_CHG should be delayed for some time, because ++ IMX does not NACK the host when CFG_CHG interrupt is pending. ++ There is no time to handle current CFG_CHG ++ if next CFG_CHG or SETUP packed is send immediately. ++ We have to clear CFG_CHG, start the timer and ++ NACK the host by setting CTRL_CMDOVER ++ if it sends any SETUP packet. ++ When timer expires, handler is called to handle configuration ++ changes. While CFG_CHG is not handled (set_config=1), ++ we must NACK the host to every SETUP packed. ++ This delay prevents from going out of sync with host. ++ */ ++ __raw_writel(INTR_CFG_CHG, imx_usb->base + USB_INTR); ++ imx_usb->set_config = 1; ++ mod_timer(&imx_usb->timer, jiffies + 5); ++ goto end_irq; ++ } ++ ++ if (intr & INTR_WAKEUP) { ++ if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN ++ && imx_usb->driver && imx_usb->driver->resume) ++ imx_usb->driver->resume(&imx_usb->gadget); ++ imx_usb->set_config = 0; ++ del_timer(&imx_usb->timer); ++ imx_usb->gadget.speed = USB_SPEED_FULL; ++ } ++ ++ if (intr & INTR_SUSPEND) { ++ if (imx_usb->gadget.speed != USB_SPEED_UNKNOWN ++ && imx_usb->driver && imx_usb->driver->suspend) ++ imx_usb->driver->suspend(&imx_usb->gadget); ++ imx_usb->set_config = 0; ++ del_timer(&imx_usb->timer); ++ imx_usb->gadget.speed = USB_SPEED_UNKNOWN; ++ } ++ ++ if (intr & INTR_RESET_START) { ++ __raw_writel(intr, imx_usb->base + USB_INTR); ++ udc_stop_activity(imx_usb, imx_usb->driver); ++ imx_usb->set_config = 0; ++ del_timer(&imx_usb->timer); ++ imx_usb->gadget.speed = USB_SPEED_UNKNOWN; ++ } ++ ++ if (intr & INTR_RESET_STOP) ++ imx_usb->gadget.speed = USB_SPEED_FULL; ++ + end_irq: + __raw_writel(intr, imx_usb->base + USB_INTR); + return IRQ_HANDLED; +@@ -1342,6 +1364,7 @@ int usb_gadget_unregister_driver(struct + + udc_stop_activity(imx_usb, driver); + imx_udc_disable(imx_usb); ++ del_timer(&imx_usb->timer); + + driver->unbind(&imx_usb->gadget); + imx_usb->gadget.dev.driver = NULL; +@@ -1459,6 +1482,10 @@ static int __init imx_udc_probe(struct p + usb_init_data(imx_usb); + imx_udc_init(imx_usb); + ++ init_timer(&imx_usb->timer); ++ imx_usb->timer.function = handle_config; ++ imx_usb->timer.data = (unsigned long)imx_usb; ++ + return 0; + + fail3: +@@ -1481,6 +1508,7 @@ static int __exit imx_udc_remove(struct + int i; + + imx_udc_disable(imx_usb); ++ del_timer(&imx_usb->timer); + + for (i = 0; i < IMX_USB_NB_EP + 1; i++) + free_irq(imx_usb->usbd_int[i], imx_usb); +--- a/drivers/usb/gadget/imx_udc.h ++++ b/drivers/usb/gadget/imx_udc.h +@@ -59,6 +59,7 @@ struct imx_udc_struct { + struct device *dev; + struct imx_ep_struct imx_ep[IMX_USB_NB_EP]; + struct clk *clk; ++ struct timer_list timer; + enum ep0_state ep0state; + struct resource *res; + void __iomem *base; diff --git a/usb/usb-usb-serial-ch341-support-for-dtr-rts-cts.patch b/usb/usb-usb-serial-ch341-support-for-dtr-rts-cts.patch new file mode 100644 index 00000000000000..e089ea05f8a98f --- /dev/null +++ b/usb/usb-usb-serial-ch341-support-for-dtr-rts-cts.patch @@ -0,0 +1,547 @@ +From boris@hajduk.org Sun Jan 25 15:19:52 2009 +From: Werner Cornelius <werner@cornelius-consult.de> +Date: Fri, 16 Jan 2009 21:02:41 +0100 +Subject: USB: usb-serial ch341: support for DTR/RTS/CTS +To: gregkh@suse.de +Cc: linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org +Message-ID: <20090116200241.GA28338@zboubi.com> +Content-Disposition: inline + + +From: Werner Cornelius <werner@cornelius-consult.de> + +Fixup of Werner Cornelius patch to the ch341 USB-serial driver, which adds: +- support all baudrates, not just a hard-coded set +- support for controlling DTR, RTS and CTS + +Features still missing: +- character length other than 8 bits +- parity settings +- break control + +I adapted his patch for the new usb_serial API introduced in 2.6.25-git8 by +Alan Cox on 22 July 2008. Non-compliance to the new API was a reason for +refusing a similar patch from Tollef Fog Heen. + +Usage example by Tollef Fog Heen : + TEMPer USB thermometer <http://err.no/src/TEMPer.c> + +Signed-off-by: Werner Cornelius <Werner.Cornelius@cornelius-consult.de> +Signed-off-by: Boris Hajduk <boris@hajduk.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/ch341.c | 374 ++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 302 insertions(+), 72 deletions(-) + +--- a/drivers/usb/serial/ch341.c ++++ b/drivers/usb/serial/ch341.c +@@ -1,5 +1,7 @@ + /* + * Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk> ++ * Copyright 2007, Werner Cornelius <werner@cornelius-consult.de> ++ * Copyright 2009, Boris Hajduk <boris@hajduk.org> + * + * ch341.c implements a serial port driver for the Winchiphead CH341. + * +@@ -21,9 +23,39 @@ + #include <linux/usb/serial.h> + #include <linux/serial.h> + +-#define DEFAULT_BAUD_RATE 2400 ++#define DEFAULT_BAUD_RATE 9600 + #define DEFAULT_TIMEOUT 1000 + ++/* flags for IO-Bits */ ++#define CH341_BIT_RTS (1 << 6) ++#define CH341_BIT_DTR (1 << 5) ++ ++/******************************/ ++/* interrupt pipe definitions */ ++/******************************/ ++/* always 4 interrupt bytes */ ++/* first irq byte normally 0x08 */ ++/* second irq byte base 0x7d + below */ ++/* third irq byte base 0x94 + below */ ++/* fourth irq byte normally 0xee */ ++ ++/* second interrupt byte */ ++#define CH341_MULT_STAT 0x04 /* multiple status since last interrupt event */ ++ ++/* status returned in third interrupt answer byte, inverted in data ++ from irq */ ++#define CH341_BIT_CTS 0x01 ++#define CH341_BIT_DSR 0x02 ++#define CH341_BIT_RI 0x04 ++#define CH341_BIT_DCD 0x08 ++#define CH341_BITS_MODEM_STAT 0x0f /* all bits */ ++ ++/*******************************/ ++/* baudrate calculation factor */ ++/*******************************/ ++#define CH341_BAUDBASE_FACTOR 1532620800 ++#define CH341_BAUDBASE_DIVMAX 3 ++ + static int debug; + + static struct usb_device_id id_table [] = { +@@ -34,9 +66,12 @@ static struct usb_device_id id_table [] + MODULE_DEVICE_TABLE(usb, id_table); + + struct ch341_private { +- unsigned baud_rate; +- u8 dtr; +- u8 rts; ++ spinlock_t lock; /* access lock */ ++ wait_queue_head_t delta_msr_wait; /* wait queue for modem status */ ++ unsigned baud_rate; /* set baud rate */ ++ u8 line_control; /* set line control value RTS/DTR */ ++ u8 line_status; /* active status of modem control inputs */ ++ u8 multi_status_change; /* status changed multiple since last call */ + }; + + static int ch341_control_out(struct usb_device *dev, u8 request, +@@ -72,37 +107,28 @@ static int ch341_set_baudrate(struct usb + { + short a, b; + int r; ++ unsigned long factor; ++ short divisor; + + dbg("ch341_set_baudrate(%d)", priv->baud_rate); +- switch (priv->baud_rate) { +- case 2400: +- a = 0xd901; +- b = 0x0038; +- break; +- case 4800: +- a = 0x6402; +- b = 0x001f; +- break; +- case 9600: +- a = 0xb202; +- b = 0x0013; +- break; +- case 19200: +- a = 0xd902; +- b = 0x000d; +- break; +- case 38400: +- a = 0x6403; +- b = 0x000a; +- break; +- case 115200: +- a = 0xcc03; +- b = 0x0008; +- break; +- default: ++ ++ if (!priv->baud_rate) + return -EINVAL; ++ factor = (CH341_BAUDBASE_FACTOR / priv->baud_rate); ++ divisor = CH341_BAUDBASE_DIVMAX; ++ ++ while ((factor > 0xfff0) && divisor) { ++ factor >>= 3; ++ divisor--; + } + ++ if (factor > 0xfff0) ++ return -EINVAL; ++ ++ factor = 0x10000 - factor; ++ a = (factor & 0xff00) | divisor; ++ b = factor & 0xff; ++ + r = ch341_control_out(dev, 0x9a, 0x1312, a); + if (!r) + r = ch341_control_out(dev, 0x9a, 0x0f2c, b); +@@ -110,19 +136,18 @@ static int ch341_set_baudrate(struct usb + return r; + } + +-static int ch341_set_handshake(struct usb_device *dev, +- struct ch341_private *priv) ++static int ch341_set_handshake(struct usb_device *dev, u8 control) + { +- dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts); +- return ch341_control_out(dev, 0xa4, +- ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0); ++ dbg("ch341_set_handshake(0x%02x)", control); ++ return ch341_control_out(dev, 0xa4, ~control, 0); + } + +-static int ch341_get_status(struct usb_device *dev) ++static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv) + { + char *buffer; + int r; + const unsigned size = 8; ++ unsigned long flags; + + dbg("ch341_get_status()"); + +@@ -134,10 +159,15 @@ static int ch341_get_status(struct usb_d + if (r < 0) + goto out; + +- /* Not having the datasheet for the CH341, we ignore the bytes returned +- * from the device. Return error if the device did not respond in time. +- */ +- r = 0; ++ /* setup the private status if available */ ++ if (r == 2) { ++ r = 0; ++ spin_lock_irqsave(&priv->lock, flags); ++ priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT; ++ priv->multi_status_change = 0; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ } else ++ r = -EPROTO; + + out: kfree(buffer); + return r; +@@ -180,7 +210,7 @@ static int ch341_configure(struct usb_de + goto out; + + /* expect 0xff 0xee */ +- r = ch341_get_status(dev); ++ r = ch341_get_status(dev, priv); + if (r < 0) + goto out; + +@@ -192,12 +222,12 @@ static int ch341_configure(struct usb_de + if (r < 0) + goto out; + +- r = ch341_set_handshake(dev, priv); ++ r = ch341_set_handshake(dev, priv->line_control); + if (r < 0) + goto out; + + /* expect 0x9f 0xee */ +- r = ch341_get_status(dev); ++ r = ch341_get_status(dev, priv); + + out: kfree(buffer); + return r; +@@ -216,9 +246,10 @@ static int ch341_attach(struct usb_seria + if (!priv) + return -ENOMEM; + ++ spin_lock_init(&priv->lock); ++ init_waitqueue_head(&priv->delta_msr_wait); + priv->baud_rate = DEFAULT_BAUD_RATE; +- priv->dtr = 1; +- priv->rts = 1; ++ priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR; + + r = ch341_configure(serial->dev, priv); + if (r < 0) +@@ -231,6 +262,35 @@ error: kfree(priv); + return r; + } + ++static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port, ++ struct file *filp) ++{ ++ struct ch341_private *priv = usb_get_serial_port_data(port); ++ unsigned long flags; ++ unsigned int c_cflag; ++ ++ dbg("%s - port %d", __func__, port->number); ++ ++ /* shutdown our urbs */ ++ dbg("%s - shutting down urbs", __func__); ++ usb_kill_urb(port->write_urb); ++ usb_kill_urb(port->read_urb); ++ usb_kill_urb(port->interrupt_in_urb); ++ ++ if (tty) { ++ c_cflag = tty->termios->c_cflag; ++ if (c_cflag & HUPCL) { ++ /* drop DTR and RTS */ ++ spin_lock_irqsave(&priv->lock, flags); ++ priv->line_control = 0; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ch341_set_handshake(port->serial->dev, 0); ++ } ++ } ++ wake_up_interruptible(&priv->delta_msr_wait); ++} ++ ++ + /* open this device, set default parameters */ + static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp) +@@ -242,14 +302,13 @@ static int ch341_open(struct tty_struct + dbg("ch341_open()"); + + priv->baud_rate = DEFAULT_BAUD_RATE; +- priv->dtr = 1; +- priv->rts = 1; ++ priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR; + + r = ch341_configure(serial->dev, priv); + if (r) + goto out; + +- r = ch341_set_handshake(serial->dev, priv); ++ r = ch341_set_handshake(serial->dev, priv->line_control); + if (r) + goto out; + +@@ -257,6 +316,16 @@ static int ch341_open(struct tty_struct + if (r) + goto out; + ++ dbg("%s - submitting interrupt urb", __func__); ++ port->interrupt_in_urb->dev = serial->dev; ++ r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); ++ if (r) { ++ dev_err(&port->dev, "%s - failed submitting interrupt urb," ++ " error %d\n", __func__, r); ++ ch341_close(tty, port, NULL); ++ return -EPROTO; ++ } ++ + r = usb_serial_generic_open(tty, port, filp); + + out: return r; +@@ -270,38 +339,194 @@ static void ch341_set_termios(struct tty + { + struct ch341_private *priv = usb_get_serial_port_data(port); + unsigned baud_rate; ++ unsigned long flags; + + dbg("ch341_set_termios()"); + ++ if (!tty || !tty->termios) ++ return; ++ + baud_rate = tty_get_baud_rate(tty); + +- switch (baud_rate) { +- case 2400: +- case 4800: +- case 9600: +- case 19200: +- case 38400: +- case 115200: +- priv->baud_rate = baud_rate; +- break; +- default: +- dbg("Rate %d not supported, using %d", +- baud_rate, DEFAULT_BAUD_RATE); +- priv->baud_rate = DEFAULT_BAUD_RATE; ++ priv->baud_rate = baud_rate; ++ ++ if (baud_rate) { ++ spin_lock_irqsave(&priv->lock, flags); ++ priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ch341_set_baudrate(port->serial->dev, priv); ++ } else { ++ spin_lock_irqsave(&priv->lock, flags); ++ priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS); ++ spin_unlock_irqrestore(&priv->lock, flags); + } + +- ch341_set_baudrate(port->serial->dev, priv); ++ ch341_set_handshake(port->serial->dev, priv->line_control); + + /* Unimplemented: + * (cflag & CSIZE) : data bits [5, 8] + * (cflag & PARENB) : parity {NONE, EVEN, ODD} + * (cflag & CSTOPB) : stop bits [1, 2] + */ ++} ++ ++static int ch341_tiocmset(struct tty_struct *tty, struct file *file, ++ unsigned int set, unsigned int clear) ++{ ++ struct usb_serial_port *port = tty->driver_data; ++ struct ch341_private *priv = usb_get_serial_port_data(port); ++ unsigned long flags; ++ u8 control; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ if (set & TIOCM_RTS) ++ priv->line_control |= CH341_BIT_RTS; ++ if (set & TIOCM_DTR) ++ priv->line_control |= CH341_BIT_DTR; ++ if (clear & TIOCM_RTS) ++ priv->line_control &= ~CH341_BIT_RTS; ++ if (clear & TIOCM_DTR) ++ priv->line_control &= ~CH341_BIT_DTR; ++ control = priv->line_control; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ return ch341_set_handshake(port->serial->dev, control); ++} ++ ++static void ch341_read_int_callback(struct urb *urb) ++{ ++ struct usb_serial_port *port = (struct usb_serial_port *) urb->context; ++ unsigned char *data = urb->transfer_buffer; ++ unsigned int actual_length = urb->actual_length; ++ int status; ++ ++ dbg("%s (%d)", __func__, port->number); ++ ++ switch (urb->status) { ++ case 0: ++ /* success */ ++ break; ++ case -ECONNRESET: ++ case -ENOENT: ++ case -ESHUTDOWN: ++ /* this urb is terminated, clean up */ ++ dbg("%s - urb shutting down with status: %d", __func__, ++ urb->status); ++ return; ++ default: ++ dbg("%s - nonzero urb status received: %d", __func__, ++ urb->status); ++ goto exit; ++ } ++ ++ usb_serial_debug_data(debug, &port->dev, __func__, ++ urb->actual_length, urb->transfer_buffer); ++ ++ if (actual_length >= 4) { ++ struct ch341_private *priv = usb_get_serial_port_data(port); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ priv->line_status = (~(data[2])) & CH341_BITS_MODEM_STAT; ++ if ((data[1] & CH341_MULT_STAT)) ++ priv->multi_status_change = 1; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ wake_up_interruptible(&priv->delta_msr_wait); ++ } ++ ++exit: ++ status = usb_submit_urb(urb, GFP_ATOMIC); ++ if (status) ++ dev_err(&urb->dev->dev, ++ "%s - usb_submit_urb failed with result %d\n", ++ __func__, status); ++} ++ ++static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) ++{ ++ struct ch341_private *priv = usb_get_serial_port_data(port); ++ unsigned long flags; ++ u8 prevstatus; ++ u8 status; ++ u8 changed; ++ u8 multi_change = 0; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ prevstatus = priv->line_status; ++ priv->multi_status_change = 0; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ while (!multi_change) { ++ interruptible_sleep_on(&priv->delta_msr_wait); ++ /* see if a signal did it */ ++ if (signal_pending(current)) ++ return -ERESTARTSYS; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ status = priv->line_status; ++ multi_change = priv->multi_status_change; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ changed = prevstatus ^ status; ++ ++ if (((arg & TIOCM_RNG) && (changed & CH341_BIT_RI)) || ++ ((arg & TIOCM_DSR) && (changed & CH341_BIT_DSR)) || ++ ((arg & TIOCM_CD) && (changed & CH341_BIT_DCD)) || ++ ((arg & TIOCM_CTS) && (changed & CH341_BIT_CTS))) { ++ return 0; ++ } ++ prevstatus = status; ++ } ++ ++ return 0; ++} ++ ++/*static int ch341_ioctl(struct usb_serial_port *port, struct file *file,*/ ++static int ch341_ioctl(struct tty_struct *tty, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct usb_serial_port *port = tty->driver_data; ++ dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); ++ ++ switch (cmd) { ++ case TIOCMIWAIT: ++ dbg("%s (%d) TIOCMIWAIT", __func__, port->number); ++ return wait_modem_info(port, arg); ++ ++ default: ++ dbg("%s not supported = 0x%04x", __func__, cmd); ++ break; ++ } ++ ++ return -ENOIOCTLCMD; ++} ++ ++static int ch341_tiocmget(struct tty_struct *tty, struct file *file) ++{ ++ struct usb_serial_port *port = tty->driver_data; ++ struct ch341_private *priv = usb_get_serial_port_data(port); ++ unsigned long flags; ++ u8 mcr; ++ u8 status; ++ unsigned int result; ++ ++ dbg("%s (%d)", __func__, port->number); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ mcr = priv->line_control; ++ status = priv->line_status; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ result = ((mcr & CH341_BIT_DTR) ? TIOCM_DTR : 0) ++ | ((mcr & CH341_BIT_RTS) ? TIOCM_RTS : 0) ++ | ((status & CH341_BIT_CTS) ? TIOCM_CTS : 0) ++ | ((status & CH341_BIT_DSR) ? TIOCM_DSR : 0) ++ | ((status & CH341_BIT_RI) ? TIOCM_RI : 0) ++ | ((status & CH341_BIT_DCD) ? TIOCM_CD : 0); ++ ++ dbg("%s - result = %x", __func__, result); + +- /* Copy back the old hardware settings */ +- tty_termios_copy_hw(tty->termios, old_termios); +- /* And re-encode with the new baud */ +- tty_encode_baud_rate(tty, baud_rate, baud_rate); ++ return result; + } + + static struct usb_driver ch341_driver = { +@@ -317,12 +542,17 @@ static struct usb_serial_driver ch341_de + .owner = THIS_MODULE, + .name = "ch341-uart", + }, +- .id_table = id_table, +- .usb_driver = &ch341_driver, +- .num_ports = 1, +- .open = ch341_open, +- .set_termios = ch341_set_termios, +- .attach = ch341_attach, ++ .id_table = id_table, ++ .usb_driver = &ch341_driver, ++ .num_ports = 1, ++ .open = ch341_open, ++ .close = ch341_close, ++ .ioctl = ch341_ioctl, ++ .set_termios = ch341_set_termios, ++ .tiocmget = ch341_tiocmget, ++ .tiocmset = ch341_tiocmset, ++ .read_int_callback = ch341_read_int_callback, ++ .attach = ch341_attach, + }; + + static int __init ch341_init(void) |
